如何使用设计模式来构造系统(2) 四

 

(由于篇幅有限,部分代码请看如何使用设计模式来构造系统--(1) )

 

上一篇我们分析了员工,工资,以及绩效奖金三个类,并且使用了Bridge和Stratege两种模式,对他们之间的组合和行为进行了设计,但是我们的设计并不完善。我们知道员工的基本工资可能每年都不一样,甚至有可能随时地根据公司的制度发生变化,而设计的根本意图就是去封装变化,让我们的系统更加的长寿,不会因为变化而大量的重造,我们怎么去避免工资变化时,员工类不改变呢??

先看一下,上次设计的员工类的代码:

 

 


public abstract class AbstractPerson
     {
            
protected string _personName;  //员工姓名
            protected Salary _personSalary; //员工工资

             
public string PersonName
            {
                
get { return _personName; }
                
set { _personName = value; }
            }
             
public Salary PersonSalary
             {
                 
get { return _personSalary; }
                 
set { _personSalary = value; }
             }
             
public abstract double GetShouldpaid(IPrize prize);
     }

    
public  class Staff : AbstractPerson
     {
        
public override double GetShouldpaid(IPrize prize)
        {
            _personSalary 
= new SttafSalary(); //初始化正式员工的基本工资
            _personSalary.Salaryprize = prize; //赋予绩效
            return _personSalary.GetShouldpaid();
        }
     }
   

这里我们看到在初始化员工工资时出现了new SttafSalary(),这就使Person与SttafSalary产生了紧耦合,也就是说SttafSalary的变化会影响Person类的稳定。那么使用何种设计模式来封装这种创建时的变化呢?

GOF23中的Factory Method(工厂方法): 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。

工厂方法的意图和我们要封装的变化意图相同,那么我们就用它来设计吧,看看类图:

 

 

 

我们使用两个同接口的工厂来封装创建时的变化,这样你在各个工厂中去添加或修改你的业务都不会影响到Person,当然原来的那种直接new的方法也不会改变,但是当你的员工类包含的工资类发生变化时(比方说现在InterShip的工资升级为正式员工的工资,而正式员工的工资重新定义),就不能应对变化了,但是将创建工作封装到Factory,就可以避免这种变化引起的Person类的修改,而只需要去添加Salary的子类,修改Factory的子类,就可以完成了。

我们来看代码。

 

工厂部分的实现:

 


  public abstract class SalaryFactory
    {
        
public abstract Salary GetSalary();  //留给具体某种工资福利制度工厂去实现
    }
    
public class StaffSalaryFactory:SalaryFactory
    {
        
public override Salary GetSalary()  //具体某种工资福利制度工厂
        {
            
return new SttafSalary();
        }
    }
    
public class InternshipSalaryFactory:SalaryFactory
    {
        
public override Salary GetSalary()  //具体某种工资福利制度工厂
        {
            
return new InternshipSalary();
        }
    }

 

Person类的实现:

 


  public abstract class AbstractPerson
     {
            
#region 字段
            
protected string _personName;  //员工姓名
            protected Salary _personSalary; //员工工资

            
#endregion

            
#region 属性

             
public string PersonName
            {
                
get { return _personName; }
                
set { _personName = value; }
            }

             
public Salary PersonSalary
             {
                 
get { return _personSalary; }
                 
set { _personSalary = value; }
             }
            
#endregion

             
public abstract double GetShouldpaid(IPrize prize);
     }

    
public  class Staff : AbstractPerson
     {
        
public override double GetShouldpaid(IPrize prize)
        {
            _personSalary 
= new StaffSalaryFactory().GetSalary();
            _personSalary.Salaryprize 
= prize;
            
return _personSalary.GetShouldpaid();
        }
     }
    
public class Internship : AbstractPerson
    {

        
public override double GetShouldpaid(IPrize prize)
        {
            _personSalary 
= new InternshipSalaryFactory().GetSalary();
            _personSalary.Salaryprize 
= prize;
            
return _personSalary.GetShouldpaid();
        }
    }

 

OK,这样我们就完成了这种变化的封装。在实际项目中你可以把Person中创建具体那个工厂,在配置文件中存储,然后做个Switch ,就可以让他们的结合更松散了,这里就不多说了。

 

接下来我们还有一个问题,Prize绩效的制度,上一篇的设计,每一个员工的工资都会创建一个Prize,而Prize只是固定的制度,员工都是遵守和共享这个制度的,这样就造成了内存的浪费,怎么去解决这个问题呢,让系统中只存在我们想要的固定数目的Prize的实例呢?

Singleton(单件):保证一个类仅有一个实例,并提供一个访问它的全局访问点。和我们的意图一样,那就用它吧。

 


 public interface IPrize
    {
        
double GetPrize(Salary salary);
    }
    
public class BadPrize : IPrize //绩效不好的奖金比率
    {
        
public static readonly BadPrize badPrize = new BadPrize(); //在这里使用静态只读,做到badPrize不可被修改
        private BadPrize()//在这里使用私有构造,做到BadPrize类不可被实例化
        { }
        
public double GetPrize(Salary salary)
        {
            
return salary.SalaryNum * 0.5;  //干的不好奖金扣一半
        }
    }

    
public class GoodPrize : IPrize  //绩效好的奖金比率
    {
        
public static readonly GoodPrize goodPrize = new GoodPrize();
        
private GoodPrize()
        { }
        
public double GetPrize(Salary salary)
        {
            
return salary.SalaryNum * 1;  //干的好奖金全发,哈哈
        }
    }

 

这样我们就保证了,在系统运行时BadPrize和GoodPrize都只有一个实例,完成了我们的设计。

 

现在来看看调用程序:

 


 class Program
    {
        
static void Main(string[] args)
        {
            Staff staff 
= new Staff();
            staff.PersonName
="涵舍愚人";
            Console.Write(staff.PersonName 
+ "本月实发工资为" + staff.GetShouldpaid(BadPrize.badPrize));  //由原先的new BadPrize(),变为现在的单件badPrize
            Console.Read();
        }
    }

 

 

输出结果:

 

 

由于这个月干的不好,绩效工资被扣一半.....:(

 

 

我们使用了两种设计模式Factory Method和Singleton ,来封装了员工的工资创建和绩效工资的单件,好了这样我们就设计完成了用户的需求,下一篇中可恶的客户要添加需求了。。(在实际开发中这种事情的发生频率,地球上的程序员都知道啦。)

原文地址:https://www.cnblogs.com/sier/p/5676520.html