设计模式系列之六:策略模式

前言

策略模式是设计模式中的行为型模式,所谓行为型就是其主要使用在方法有很大灵活性的情况。而之前的工厂模式主要是对创建对象的优化,减少程序中使用new对象的次数。策略模式在Java源码中也是很常见的,比如我们要比较两个对象的大小,既可以使用默认的Comparable接口,也可以实现自定义的比较规则,即实现Comparator接口。这两种比较比较方法都是不同比较规则的体现,属于不同的策略。策略模式从定义上是这么说的:定义了算法家族,把这些不同的算法封装起来,让他们之间可以相互替换。从而使得算法的替换不会影响调用者的变化。光从字面上感觉还不是特别清晰,简单来说就是要办成一件事可以有不同的方法,这些方法都是属于一个家族的,所以从本质上来讲,这些方法是没有区别的。因为外界调用的时候只需要知道这个家族的代表是谁就可以了,其他的调用者并不需要关心。

问题背景

实现一个收银软件,输入单价与数量计算总价格。商场的收费方式可能有多种而且还会随时改变。

编码实践一,使用简单工厂模式实现

//SimpleFactory Mode
public abstract class Cash{
    public abstract double calculateRealCash(double money);
}

public class NormalCash extends Cash{
    public double calculateRealCash(double money){
        return money;
    }
}

public class DiscountCash extends Cash{
    //打折点
    private double discountPoint;

    public DiscountCash(double discountPoint){
        this.discountPoint = discountPoint;
    }

    public double getDiscountPoint(){
        return discountPoint;
    }

    public void setDiscountPoint(double discountPoint){
        this.discountPoint = discountPoint;
    }

    public double calculateRealCash(double money){
        return Math.floor(money * discountPoint);
    }
}

public class RebateCash extends Cash{

    private String rebateCondition;
    private String moneyOfRebate;

    public RebateCash(String rebateCondition,String moneyOfRebate){
        this.rebateCondition = rebateCondition;
        this.moneyOfRebate = moneyOfRebate;
    }

    public String getRebateCOndition(){return rebateCondition;}
    public void setRebateCondition(String rebateCondition){this.rebateCondition = rebateCondition;}
    public String getMoneyOfReabte(){return moneyOfRebate;}
    public void setMoneyOfReabte(String moneyOfRebate){this.moneyOfRebate = moneyOfRebate;} 

    public double calculateRealCash(double money){
        return money > Double.valueOf(rebateCondition) ? money - Math.floor(money * Double.valueOf(moneyOfRebate) / Double.valueOf(rebateCondition)) : money;
    }
}

public class CashFactory{

    public static Cash createCashObject(int type){
        Cash cash = null;;
        switch(type){
            case 1:
                cash = new NormalCash();
                break;
            case 2:
                cash = new DiscountCash(0.85);
                break;
            case 3:
                cash = new RebateCash("300","100");
                break;
            default:
                cash = new NormalCash();
                break;
        }
        return cash;
    }
}

public class Test{
    public static void main(String[] args){
    Scanner in = new Scanner(System.in);

    System.out.println("price:");
    double price = in.nextDouble();
    System.out.println("num:");
    int num = in.nextInt();
    double price2 = num * price;

    System.out.println("Choose type to calculate the total price:\n"
        + " 1 is normal cash\n 2 is 80% discount cash\n 3 is full 300 return 100");

    int type = in.nextInt();

    Cash cash = CashFactory.createCashObject(type);
    System.out.println("Total price is " + totalPrice);
    }
}

测试结果:

编码实践二,使用策略模式实现

public class CashContext{
    private Cash cash;

    public CashContext(int type){
        switch(type){
            case 1:
                cash = sm.new NormalCash();
                break;
            case 2:
                cash = sm.new DiscountCash(0.85);
                break;
            case 3:
                cash = sm.new RebateCash("300","100");
                break;
        }
    }

    public double getRealMoney(double money){
        return cash.calculateRealCash(money);
    }
}

//测试
public class Test{
    public static void main(String[] args){
    Scanner in = new Scanner(System.in);

    System.out.println("price:");
    double price = in.nextDouble();
    System.out.println("num:");
    int num = in.nextInt();
    double price2 = num * price;

    System.out.println("Choose type to calculate the total price:\n"
        + " 1 is normal cash\n 2 is 80% discount cash\n 3 is full 300 return 100");

    int type = in.nextInt();

    CashContext cashContext = new CashContext(type);
    double totalPrice = cashContext.getRealMoney(price2);
    System.out.println("Total price is " + totalPrice);
    }
}

测试结果2:

OK,现在使用两种方法的测试结果是一致的,那么来看看两种设计模式的区别。对比类CashContextCashFactory我们可以发现,策略模式封装了一个Cash对象,而这个对象是所有收费方法类的超类,那么在计算最后的钱数的时候,CashContext只是创建了一个实例,使用了一个CashContext类,而使用简单工厂模式在计算的时候,使用了CashFactory和Cash两个类,那么使用类的个数的多少又有什么关系呢?在Java中提倡依赖倒转原则,意思就是要要面向抽象编程而不是面向细节编程。延伸来讲就是,对外暴露的细节越少越好,因为对外暴露的细节越少,因需求变更而修改的代码越少,同时这也是开放-封闭原则的体现,所以从这点讲简单工厂模式对外暴露的字节大于策略模式,所以在面向抽象编程上更胜一筹。当然策略模式也有其不足,比如在构造函数中添加了逻辑判断语句,,与使用构造函数的初衷不是很符合,所以创建一个单独的方法或者类来单独完成类实例化的工作会更好一些。注意到,前面的CashFactory类的createCashObject()方法正是用来创建Cash对象的,所以可以把CashContext构造函数创建Cash对象的方法直接改为createCashObject()方法。这样每一个类的调用关系又进一步解耦了。

最后,对策略模式做一个简单的总结:

  1. 每个算法类封装了不同的实现,但完成的是相同的工作。这样就把算法实现类与使用算法类的类解耦
  2. 简化了单元测试
  3. 对外部暴露了更少的实现细节,符合开放-封闭原则
  4. 当算法实现类不断增加的时候,在Context类中增加的switch分支会越来越多
时间: 2025-01-21 19:28:00

设计模式系列之六:策略模式的相关文章

【设计模式系列】--策略模式

什么是策略模式 在前面的博文中,小编主要向小伙伴介绍了组合模式,今天这篇博文,我们继续来学习设计模式的相关知识,今天和小伙伴们见面的是策略模式,策略模式英文名字叫Strategy,策略模式属于行为模式的一种,她对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定,策略模式主要用来平滑的处理算法的切换. 策略模式结构图 我们来看一下策略的结构图,如下所示:   对上述结构图进行简单的解释说明:         a

C# 设计模式系列教程-策略模式_C#教程

在讲策略模式之前,我先给大家举个日常生活中的例子,从首都国际机场到XXX酒店,怎么过去?1)酒店接机服务,直接开车来接.2)打车过去.3)机场快轨+地铁 4)机场巴士 5)公交车 6)走路过去(不跑累死的话) 等等.使用方法,我们都可以达到从机场到XXX酒店的目的,对吧.那么我所列出的从机场到XXX酒店的的方法,就是我们可以选择的策略. 再举个例子,就是我们使用WCF时,往往避免不了对它进行扩展,例如授权,我们可以通过自定义授权来扩展WCF.这里我们可以通过自定义AuthorizationPol

设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述         在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法:当然也可以将这些查找算法封装在一个统一的方法中,通过if-else-或者case等条件判断语

Android设计模式系列之组合模式_Android

Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用.在android UI设计,几乎所有的widget和布局类都依靠这两个类. 组合模式,Composite Pattern,是一个非常巧妙的模式.几乎所有的面向对象系统都应用到了组合模式. 1.意图 将对象View和ViewGroup组合成树形结构以表示"部分-整体"的层次结构(View可以做为ViewGroup的一部分). 组合模式使得用户对单个对象View和组合对象ViewGrou

Android设计模式系列之组合模式

Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用.在android UI设计,几乎所有的widget和布局类都依靠这两个类. 组合模式,Composite Pattern,是一个非常巧妙的模式.几乎所有的面向对象系统都应用到了组合模式. 1.意图 将对象View和ViewGroup组合成树形结构以表示"部分-整体"的层次结构(View可以做为ViewGroup的一部分). 组合模式使得用户对单个对象View和组合对象ViewGrou

php设计模式介绍之策略模式

在编写面向对象的代码的时,有些时候你需要一个能够自己根据不同的条件来引入不同的操作对象实 例.例如,一个菜单功能能够根据用户的"皮肤"首选项来决定是否采用水平的还是垂直的 排列形式,或者一个计费系统可以自行根据用户的收货地址来决定税率. 一般来讲,一个控制菜 单的对象实例包括了add(), delete(), 和 replace()等菜单元素:并通过set()进行配置,用render() 来管理显示模式.无论你想生成什么样子的菜单,你都可以用同一个对象类来处理.不同菜单的对象实 例只是

深入解析C++编程中对设计模式中的策略模式的运用_C 语言

策略模式也是一种非常常用的设计模式,而且也不复杂.下面我们就来看看这种模式. 定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. 角色:     抽象策略角色(Strategy): 抽象策略类.     具体策略角色(ConcreteStrategy):封装了继续相关的算法和行为.     环境角色(Context):持有一个策略类的引用,最终给客户端调用. UML图: 例子: #include <iostream>

详解C++设计模式编程中策略模式的优缺点及实现_C 语言

策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法的变化不会影响到使用算法的客户.策略模式和 Template 模式要解决的问题是相同(类似)的,都是为了给业务逻辑(算法)具体实现和抽象接口之间的解耦.策略模式将逻辑(算法)封装到一个类(Context)里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给组合对象实现.State 模式也有类似的功能,他们之间的区别将在讨论中给出. UML图

举例讲解iOS应用开发中对设计模式中的策略模式的使用_IOS

策略模式是一种常见的软件设计模式,这里简单得介绍一下策略模式并用IOS简单实现一下. 所谓的策略模式,顾名思义是要采用不同的策略的.一般来说,在不同的情况下,处理某一个问题的方法也不一样.比如说对字符串的排序和对数字的排序,虽然用的都是快排,但是显然不可能使用一段通用的代码.有人说java里面的compareTo可以做到,但如果考虑这么一个问题:同样是出门旅行,老年人身体虚弱,需要大量的休息,而孩子则是精力充沛,希望玩到更多的景点.如何在同一模式下表达以上信息.采用合理的设计模式进行封装而不是大