设计模式(策略模式,单例模式)

来源:互联网 发布:php 时间轴 编辑:程序博客网 时间:2024/05/29 18:35

可参考链接http://developer.51cto.com/art/201301/376831.htm《如何向妻子解释设计模式》

 

设计模式蕴含的几种基本原则:里氏替换原则,开闭原则,合成复用原则,依赖倒置原则
“设计模式是为了让软件更容易让人读懂,更容易维护而产生,设计模式本质是程序员之间的交流。”

单例模式有以下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。
(e.g.每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。)

public class Singleton1
{
   
    //仅限自身调用的构造函数
    private Singleton1(){}
   
    public static Singleton1 singleton1 = null;
   
    public static Singleton1 getInstance()
    {
        if(singleton1 == null)
        {
            singleton1 = new Singleton1();
        }
        return singleton1;
    }
}
Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)

public class Singleton2
{
    private static Singleton2 singleton2 = null;
   
    public static synchronized Singleton2 getInstance()
    {
        if(singleton2 == null)
        {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

 

策略模式:封装一组算法,使它们之间可以相互转换,而对算法使用者来说不会受到影响,其实说不受到影响是指用户代码的模式一致,即不改变用户的使用习惯。策略模式把行为和环境分开。环境类负责维持和查询行为类,各种算法在具体的策略类中提供。由于算法和环境独立开来,算法的增减,修改都不会影响到环境和客户端。策略模式的设计原则即把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口,然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。

策略模式的组成:
 抽象策略角色(Strategy):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法。一般使用接口或抽象类实现。
 具体策略角色(ConcreteStrategy):包装了相关的算法和行为。
 环境角色(Context):持有一个策略类的引用,最终给客户端调用。

Context(应用场景):
1、需要使用ConcreteStrategy提供的算法。
2、内部维护一个Strategy的实例。
3、负责动态设置运行时Strategy具体的实现算法。
4、负责跟Strategy之间的交互和数据传递。

优点:
1、简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点:
   1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
         2、在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

使用
当存在以下情况时使用Strategy模式
1)许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。即一个系统需要动态地在几种算法中选择一种。
2) 需要使用一个算法的不同变体。
3)算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
4)一个类定义了多种行为 ,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句

总结
1)策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
2)在策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略角色。
3)策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。

 

案例
    ///<summary>
     /// 现金收费抽象类
     /// </summary>
     abstract class CashSuper
     {
         //现金收取超类的抽象方法,收取现金,参数为原价,返回当前价。
         public abstract doubleacceptCash(double money);
     }
/// <summary>
     /// 正常收费子类
     /// </summary>
     class CashNormal:CashSuper
     {
         public override doubleacceptCash(double money)
         {
             return money;
         }
     }
     /// <summary>
     /// 打折子类
     /// </summary>
     class CashRebate:CashSuper
     {
         private double moneyRebate = 1d;
         public CashRebate(string moneyRebate)
         {
             this.moneyRebate =double.Parse(moneyRebate);
         }
        public override doubleacceptCash(double money)
         {
             return money * moneyRebate;
         }
     }
     /// <summary>
     /// 返利子类
     /// </summary>
     class CashReturn:CashSuper
     {
         private double moneyCondition = 0.0d;
         private double moneyReturn = 0.0d;
         /// <summary>
         /// 返利子类构造方法
         /// </summary>
         /// <paramname="moneyCondition">返利标准</param>
         /// <paramname="moneyReturn">返利值</param>
         public CashReturn(stringmoneyCondition, string moneyReturn)
         {
             this.moneyCondition =double.Parse(moneyCondition);
             this.moneyReturn =double.Parse(moneyReturn);
         }
         public override doubleacceptCash(double money)
         {
             double result = money;
             if (money >= moneyCondition)
                 result = money -Math.Floor(money / moneyCondition) * moneyReturn;
             return result;
         }
     }
class CashContext
     {
         CashSuper cs;
         public CashContext(string type)
         {
            //简单工厂构造函数,克服客户端需要知道所以算法子类的缺点(封装了变化)
             switch (type)
             {
                 case "正常收费":
                     cs = new CashNormal();
                     break;
                 case "满300返100":
                     cs = newCashReturn("300", "100");
                     break;
                 case "打8折":
                     cs = newCashRebate("0.8");
                     break;
             }
         }
         //和简单工厂的不同之处
         public double GetResult(double money)
         {
             return cs.acceptCash(money);
         }
     }
CashContext csuper =new CashContext(cmbDiscount.SelectedItem.ToString());
             double totalPrices = 0d;
             totalPrices =csuper.GetResult(double.Parse(this.txtPrice.Text) *double.Parse(this.txtNumber.Text));
            this.lbxResult.Items.Add("单价:" + this.txtPrice.Text + "数量:" + this.txtNumber.Text + " " + cmbDiscount.SelectedItem +" " + "合计" + totalPrices.ToString());
             total = total + totalPrices;
             this.lblAmount.Text =total.ToString();

原创粉丝点击