zoukankan      html  css  js  c++  java
  • 设计模式------策略模式

       策略模式定义了算法家族。分别封装起来。让它们之间能够互相替换,此模式让算法的变化,不会影响到使用算法的用户。何谓算法呢?它是一种描写叙述程序行为的语言。广泛应用于计算机科学领域,是一种让程序最为简洁的思考方式。

    一、组成:

    1.抽象策略角色: 策略类,通常由一个接口或者抽象类实现。

    2.详细策略角色:包装了相关的算法和行为。

    3.环境角色:持有一个策略类的引用。终于给client调用。


    二、应用场景:

    1、多个类仅仅差别在表现行为不同。能够使用Strategy模式。在执行时动态选择详细要执行的行为。

    2、须要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其他方式来实现。

    3、对客户隐藏详细策略(算法)的实现细节。彼此全然独立。

    三、优缺点:

    1.长处:

      恰当使用继承能够把公共的代码转移到父类里面,从而避免反复的代码。将每一个算法都封装起来,而且使它们之间能够互换,client调用它们的时候互不影响。从而减少了系统的耦合度。提高了扩展性和可重用性。易于測试和维护。

    2.缺点:

      策略模式仅仅适用于client知道全部的算法或行为的情况。策略模式造成非常多的策略类。每一个详细策略类都会产生一个新类,能够使用享元模式来降低对象的数量。

    四、策略模式vs简单工厂模式:

       工厂模式是创建型模式,关注对象的创建。

    策略模式是行为型模式,关注行为的封装。简单工厂模式是依据不同的条件返回一个适合的类给你使用,然后调用者使用工厂类返回的类去完毕对应的操作。而策略模式是首先创建一个想使用的类实例。然后实例被当作參数传递进去,既而通过该实例去调用不用的算法。

    五、代码示范:

    某超市平时正常收费。周六日打八折,周年庆满300返100。

    以下我们利用已经学到的策略模式与简单工厂相结合编写一个收银程序。

    1.抽象策略类:

    //现金收取父类
    abstract class CashSuper
    {
        //抽象方法:收取现金。參数为原价,返回为当前价
        public abstract double acceptCash(double money);
    }
    2.详细策略角色:

     //正常收费,继承CashSuper
        class CashNormal : CashSuper
        {
            public override double acceptCash(double money)
            {
                return money;
            }
        }

     //打折收费。继承CashSuper
        class CashRebate : CashSuper
        {
            private double moneyRebate = 1d;
            //初始化时,必须要输入折扣率,如八折,就是0.8
            public CashRebate(string moneyRebate)
            {
                this.moneyRebate = double.Parse(moneyRebate);
            }
    
            public override double acceptCash(double money)
            {
                return money * moneyRebate;
            }
        }

     //返利收费,继承CashSuper
        class CashReturn : CashSuper
        {
            private double moneyCondition = 0.0d;
            private double moneyReturn = 0.0d;
            //初始化时必需要输入返利条件和返利值。比方满300返100。则moneyCondition为300,moneyReturn为100
            public CashReturn(string moneyCondition, string moneyReturn)
            {
                this.moneyCondition = double.Parse(moneyCondition);
                this.moneyReturn = double.Parse(moneyReturn);
            }
    
            public override double acceptCash(double money)
            {
                double result = money;
                //若大于返利条件。则需要减去返利值
                if (money >= moneyCondition)
                    result = money - Math.Floor(money / moneyCondition) * moneyReturn;
    
                return result;
            }
        }

    3.环境角色:

    class CashContext
    {
        CashSuper cs = null;
    
        //依据条件返回对应的对象
        public CashContext(string type)
        {
            switch (type)
            {
                case "正常收费":
                    CashNormal cs0 = new CashNormal();
                    cs = cs0;
                    break;
                case "满300返100":
                    CashReturn cr1 = new CashReturn("300", "100");
                    cs = cr1;
                    break;
                case "打8折":
                    CashRebate cr2 = new CashRebate("0.8");
                    cs = cr2;
                    break;
            }
        }
    
        public double GetResult(double money)
        {
            return cs.acceptCash(money);
        }
    }

    4.client:

      //client窗口程序(主要部分)
            double total = 0.0d;
            private void btnOk_Click(object sender, EventArgs e)
            {
                //利用简单工厂模式依据下拉选择框,生成对应的对象
                CashContext csuper = new CashContext(cbxType.SelectedItem.ToString());
                double totalPrices = 0d;
                //通过多态。能够得到收取费用的结果
                totalPrices = csuper.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
                total = total + totalPrices;
                lbxList.Items.Add("单位价格:" + txtPrice.Text + " 数量:" + txtNum.Text + " "
                    + cbxType.SelectedItem + " 合计:" + totalPrices.ToString());
                lblResult.Text = total.ToString();
            }
    5.窗口展示:


           

    6.假设不使用策略模式。仅仅用简单工厂实现,会如何呢?请看client的代码。

    //client窗口程序(主要部分)
            double total = 0.0d;
            private void btnOk_Click(object sender, EventArgs e)
            {
                //利用简单工厂模式依据下拉选择框,生成对应的对象
                CashSuper csuper = CashFactory.createCashAccept(cbxType.SelectedItem.ToString());
                double totalPrices = 0d;
                //通过多态,能够得到收取费用的结果
                totalPrices = csuper.acceptCash(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));
                total = total + totalPrices;
                lbxList.Items.Add("单位价格:" + txtPrice.Text + " 数量:" + txtNum.Text + " "
                    + cbxType.SelectedItem + " 合计:" + totalPrices.ToString());
                lblResult.Text = total.ToString();
            }
          

         假设不使用策略模式,超市须要常常性地更改收费方式。每次维护和扩展都要去修改CashFactory,又一次编译部署代码,这样就非常麻烦了。

    策略模式定义了一系列算法(收费方式)的方法,这些算法完毕的都是同样的工作,那就是GetResult。应用简单工厂把实例化详细策略类的过程由client转移到Context类中,这样client仅仅需认识一个类CashContext,详细的收费算法彻底地与client分离,从而减少了耦合度,易于维护。

        有了这种的程序,收银员即使没学过数学也能胜任这份工作,仅仅需在组合框中选择正确的收费方式,然后去扫码就能够了。超市打折时。不必去数据库中一个一个修改商品的价格。也不必耗费时间和劳动力去给商品又一次贴价格了。

        变是永远不变的。假设超市要打九折、满200返50呢,怎样避免更改CashContext中的代码呢?这就要用到我们以后要学的反射技术了。办法总是比困难多的。

    一款好的软件尽管是看不见摸不着的,但它们发挥的作用却是不可估量的,所以好好学设计模式吧。设计出优秀的软件,为人民服务!



  • 相关阅读:
    新建maven web工程报错
    Linux的系统suspend和resume
    Linux内核配置---menuconfig
    printk()函数学习笔记
    驱动调试笔记
    i2c接口笔记
    无线路由器的加密模式WEP,WPA-PSK(TKIP),WPA2-PSK(AES) WPA-PSK(TKIP)+WPA2-PSK(AES)。
    Linux下sniffer实现(转)
    驱动模块(3)——Linux交叉编译工具链
    ehci ohci 驱动逻辑
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6789791.html
Copyright © 2011-2022 走看看