设计模式,策略模式

策略模式概述

策略模式,即与解决问题的策略有关的模式,该模式旨在更好的实现策略的实现。策略模式分为三个部分:环境、抽象策略角色、具体策略角色。策略模式能使得更好地管理和使用一类算法。

  • 环境(context):用于确定对应的具体策略角色。并将解决策略的功能最终放在环境context中(只要向下调用功能即可)。
  • 抽象策略角色:能完成一种问题的解决的各种算法的范称,通常为接口,定义能解决问题的功能,但是不实现,具体的算法的步骤由实现类解决。
  • 具体策略角色:实现抽象策略角色,要完成具体的解决问题的功能的角色。

代码实现举例

如果一家商场能让顾客办会员卡以达到优惠的目的,而会员卡分为两种:八折卡、满减卡(没满三百减五十)。要求输入原价格和优惠方式,得到优惠后的价格。

分析,这里的抽象策略角色应该为优惠方式,而具体策略角色有三个:八折、满减、普通,而环境(通常用context表示)用于确定对应具体的优惠方式

抽象策略角色(优惠方式)

/**
 * 表示优惠的算法,具体优惠方式由实现类定义
 */
public interface Concession {
    //计算优惠后的价格的功能
    Double doConcession(Double price);
}

具体策略角色(优惠方式的不同具体实现)

普通:

/**
 * 没有优惠卡的计算方法
 */
public class NormalConcession implements Concession {
    @Override
    public Double doConcession(Double price) {
        return price;
    }
}

八折卡:

/**
 *  有八折卡的计算方法
 */
public class RebateConcession implements Concession {

    @Override
    public Double doConcession(Double price) {
        return price * 0.8;
    }
}

满减卡:

/**
 * 有满减卡的计算方法(每满三百减五十)
 */
public class ReturnConcession implements Concession {
    @Override
    public Double doConcession(Double price) {
        return price - ( (int)(price / 300) * 50 );
    }
}

普通策略模式的环境(context)

/**
 * 普通策略模式的Context类,用于决定不同的算法
 */
public class ConcessionContext {
    private Concession concession;
    public ConcessionContext(Concession concession){
        this.concession = concession;
    }
    public Double doConcession(Double price){
        return concession.doConcession(price);
    }
}

通过传入不同的具体策略模式的对象,来决定其成员变量concession是怎样的策略。并且将策略的功能最终放在环境中,业务代码只要调用环境的功能的方法即可。

主要业务代码

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入原价格");
        double price = scan.nextDouble();
        System.out.println("请输入优惠方式");
        String method = scan.next();
        ConcessionContext context = null;
        switch (method){
            case "普通":
                context = new ConcessionContext(new NormalConcession());
                break;
            case "八折卡":
                context = new ConcessionContext(new RebateConcession());
                break;
            case "满减卡":
                context = new ConcessionContext(new ReturnConcession());
                break;
            default:
                context = null;
                break;
        }
        if (context == null){
            throw new Exception("方式错误");
        }
        Double concession = context.doConcession(price);
        System.out.println("优惠后价格为:" + concession);
    }

但是这种方式有一些缺点:

  • 具体策略的选择在业务代码中进行,当修改底层时(比如增加、删除、更新了策略)也要修改业务代码
  • 业务代码中要实例化各种具体策略对象,使得代码繁杂,而且个人感觉这样使得环境context有点多余,在这种情况下,context只是起了一个没有中间作用的类,判断完后直接使用具体实现策略的对象调用方法差别也不大

策略模式与简单工厂模式相结合

结合的要点是,让环境context起到一个工厂类的效果,来完成实例化。并且,让context去完成具体实现策略的判断后再作对应,我们只要传入要选择的策略的标识即可(比如传入目标策略的名字,让context根据此名字来实例化对应的策略对象)。

升级版的context

/**
 * 策略者模式与简单工厂模式相结合
 */
public class ConcessionContextPlus {
    Concession context = null;
    public ConcessionContextPlus(String method) throws Exception {
        switch (method){
            case "普通":
                context = new NormalConcession();
                break;
            case "八折卡":
                context = new RebateConcession();
                break;
            case "满减卡":
                context = new ReturnConcession();
                break;
            default:
                context = null;
                break;
        }
        if (context == null) {
            throw new Exception("方式错误");
        }
    }
    public Double doConcession(Double price){
        return context.doConcession(price);
    }
}

升级后的业务代码

/**
 * 升级版业务(非常简洁,可读性高)
 */
public class MainPlus {
    public static void main(String[] args) throws Exception {
        Scanner scan = new Scanner(System.in);

        System.out.println("请输入原价格");
        double price = scan.nextDouble();

        System.out.println("请输入优惠方式");
        String method = scan.next();

        //实际上两步就完成了策略
        //传入优惠方式
        ConcessionContextPlus concessionContextPlus = new ConcessionContextPlus(method);
        //传入原价格
        Double concession = concessionContextPlus.doConcession(price);

        System.out.println("优惠后价格为" + concession);
    }
}

升级后的业务代码明显简单了很多。

总结

  • 策略模式能更好地管理和使用一类算法,在做算法增删改时,无需改动业务代码,只要对底层进行修改。使得代码的耦合度低,封装性强。
  • 策略模式结合简单工厂模式,让context起到工厂的作用,能让业务代码更为简洁,也更易于理解和使用。比起普通的策略模式,耦合度更低,封装性更强。

相关推荐

  1. 设计模式——策略模式

    2024-03-25 05:24:02       47 阅读
  2. 设计模式-策略模式

    2024-03-25 05:24:02       59 阅读
  3. 设计模式——策略模式

    2024-03-25 05:24:02       47 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-25 05:24:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-25 05:24:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-25 05:24:02       82 阅读
  4. Python语言-面向对象

    2024-03-25 05:24:02       91 阅读

热门阅读

  1. ElasticSearch插件安装及配置

    2024-03-25 05:24:02       45 阅读
  2. 设计模式--建造者模式(Builder Pattern)

    2024-03-25 05:24:02       43 阅读
  3. P - Beat

    P - Beat

    2024-03-25 05:24:02      37 阅读
  4. C语言UNIX域套接字CS模型

    2024-03-25 05:24:02       35 阅读
  5. [AIGC] OkHttp:轻松实现网络请求

    2024-03-25 05:24:02       43 阅读
  6. 智能写作利器ChatGPT:提升论文写作效率

    2024-03-25 05:24:02       49 阅读
  7. 数据分析-Pandas分类数据的比较如何避坑

    2024-03-25 05:24:02       44 阅读
  8. 在Flink SQL中使用watermark进阶功能

    2024-03-25 05:24:02       43 阅读
  9. 使用docker搭建dockge

    2024-03-25 05:24:02       40 阅读
  10. 自学python指导教程

    2024-03-25 05:24:02       35 阅读