zoukankan      html  css  js  c++  java
  • 如何使用设计模式来构造系统(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 ,来封装了员工的工资创建和绩效工资的单件,好了这样我们就设计完成了用户的需求,下一篇中可恶的客户要添加需求了。。(在实际开发中这种事情的发生频率,地球上的程序员都知道啦。)

  • 相关阅读:
    实验四
    实验一、二
    实验
    网上摘录
    网上摘录(琐碎信息)
    angularJsUIbootstrap系列教程1(使用前的准备)
    angularJS在本机运行时的注意事项
    angularJS在创建指令需要注意的问题(指令中使用ngRepeat)
    angularJsUIbootstrap系列教程2(According)
    ASP.NET Web Forms 4.5的新特性
  • 原文地址:https://www.cnblogs.com/sier/p/5676520.html
Copyright © 2011-2022 走看看