• 策略模式


    一、概念

    策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)

     

    图1 策略模式类图

     优点:

      1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
      2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
          3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

      缺点:
      1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
          2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

    参考阅读:
    1. 2.

     二、我的理解

    其实这个策略模式和简单工厂模式一样,仅仅是对面向对象继承中常用的Override技术的一种应用。简单工厂模式中有一个工厂类,负责根据输入参数的不同来生成不同的子类,并将生成的子类作为基类返回(这样可以让客户端在使用的时候很方便)。客户端只需要调用工厂类创建一个基类的实例,然后调用这个实例的函数来实现自己的功能。而策略模式中的Context类的功能基本上就是对工厂类的强化版本,它也负责根据输入参数来生成不同的类,只是它并不返回生成类,而是将生成类所实现的功能接口包装一次,提供给客户。这样对客户来说,他们只需要知道这一个Context类就可以完成他们想要的功能,而不必再知道其他的信息。

    三、策略模式与简单工厂模式结合的代码实现

    下面以一个简单的商场收银系统为例,演示一下策略模式与简单工厂模式结合的使用。我将这个系统用两个工程实现。一个工程实现商场计费的业务功能,另一个工程用于实现POS机上的界面,也就是客户端。

    首先介绍第一个工程:

    1. 实现计费功能的基类(这里用抽象类实现): 


    1 namespace ColinSong.DesignPattern.Strategy
    2 {
    3     public abstract class BillingAlgorithm
    4     {
    5         public abstract double getBillingResult(double price, int quantity);
    6     }
    7 }

    2. 实现具体计费功能的子类:

         2.1 实现打折计费的子类:     


     1 namespace ColinSong.DesignPattern.Strategy
     2 {
     3     public class BillingStrategy_Rebate:BillingAlgorithm
     4     {
     5         double discounts;
     6         public BillingStrategy_Rebate(double discounts)
     7         {
     8             if (discounts < 0.0000001 || discounts >= 1)
     9             {
    10                 this.discounts = 1;
    11             }
    12             else
    13             {
    14                 this.discounts = discounts;
    15             }
    16         }
    17 
    18         public override double getBillingResult(double price, int quantity)
    19         {
    20             return price * quantity * discounts;
    21         }
    22     }
    23 }

         2.2 实现返现计费功能的子类:     


     1 namespace ColinSong.DesignPattern.Strategy
     2 {
     3     public class BillingStrategy_CashReturn:BillingAlgorithm
     4     {
     5         int CashCondition;
     6         int CashReturn;
     7         public BillingStrategy_CashReturn(int CashCondition, int CashReturn)
     8         {
     9             if (CashCondition <= 0)
    10             {
    11                 CashCondition = 1;
    12             }
    13             if (CashReturn <= 0)
    14             {
    15                 CashReturn = 1;
    16             }
    17             this.CashCondition = CashCondition;
    18             this.CashReturn = CashReturn;
    19         }
    20 
    21         public override double getBillingResult(double price, int quantity)
    22         {
    23             double orignal = price * quantity;
    24             int n = (int) (orignal / CashCondition);
    25             return orignal - CashReturn * n;
    26         }
    27     }
    28 }
    29 

    3. Context类


     1namespace ColinSong.DesignPattern.Strategy
     2{
     3    public class Billing
     4    {
     5        //维护一个算法基类的实例
     6        BillingAlgorithm billingAlgorithm;
     7
     8        //简单工厂模式的构造函数
     9        public Billing(string BillingStrategy)
    10        {
    11            switch (BillingStrategy)
    12            {
    13                case "打8折":
    14                    billingAlgorithm = new BillingStrategy_Rebate(0.8);
    15                    break;
    16                case "满200返40":
    17                    billingAlgorithm = new BillingStrategy_CashReturn(20040);
    18                    break;
    19                default:
    20                    billingAlgorithm = new BillingStrategy_Rebate(1);
    21                    break;
    22            }

    23        }

    24        //策略模式的构造函数
    25        public Billing(BillingAlgorithm billingAlgorithm)
    26        {
    27            this.billingAlgorithm = billingAlgorithm;
    28        }

    29        //这是策略模式的典型特征
    30        public double GetResult(double price, int quantity)
    31        {
    32            return billingAlgorithm.getBillingResult(price, quantity);
    33        }

    34    }

    35}

    36

     

    好,算法完成了,下面介绍客户端,界面如图2所示:

    图2. 商场收银系统界面

     

    下面看一下,确定按钮后面的代码:


            private void btnOK_Click(object sender, EventArgs e)
            {
                \\只需要知道这个Context类,实例化它;
                Billing billing 
    = new Billing(cbxBillingType.Text);
                \\并调用它提供的方法,即可完成我们需要的功能。
                
    double charge = billing.GetResult(double.Parse(txtPrice.Text), 
                    
    int.Parse(txtQuantity.Text));
                totalCash 
    = totalCash + charge;
                
    string itemShow = "单价:"+txtPrice.Text
                    
    + "\t数量:"+txtQuantity.Text +
                    
    ".\t实收:"+ charge.ToString()
                    
    + "\t"+cbxBillingType.Text;
                list.Items.Add(itemShow);
                lblSum.Text 
    = totalCash.ToString();
            }

     

    Over。O(∩_∩)O

     http://www.cnblogs.com/colinsong/archive/2009/03/02/1401723.html

  • 相关阅读:
    Python爬取并分析B站最热排行榜,我发现了这些秘密
    Pycharm 实现远程部署和调试,原来这么简单
    《演员请就位2》弹幕的情感倾向分析
    下个十年,Python 的“王者”地位还能保住吗?
    致初学者:如何学好Python这门编程语言?
    用Python爬取英雄联盟(lol)全部皮肤
    Python很慢?Python之父一句话亮了
    Python 国产库推荐之 musicpy
    利用VS Code进行远程开发,就问你香不香?
    包名规范
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1740059.html
Copyright © 2020-2023  润新知