设计模式,策略模式

策略模式概述

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

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

代码实现举例

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

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

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

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

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

普通:

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

八折卡:

java 复制代码
/**
 *  有八折卡的计算方法
 */
public class RebateConcession implements Concession {

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

满减卡:

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

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

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

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

主要业务代码

java 复制代码
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

java 复制代码
/**
 * 策略者模式与简单工厂模式相结合
 */
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);
    }
}

升级后的业务代码

java 复制代码
/**
 * 升级版业务(非常简洁,可读性高)
 */
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 分钟前
简识JVM的栈帧优化共享技术
java·jvm
方圆想当图灵20 分钟前
缓存之美:万文详解 Caffeine 实现原理(下)
java·redis·缓存
栗豆包34 分钟前
w175基于springboot的图书管理系统的设计与实现
java·spring boot·后端·spring·tomcat
等一场春雨1 小时前
Java设计模式 十四 行为型模式 (Behavioral Patterns)
java·开发语言·设计模式
萧若岚2 小时前
Elixir语言的Web开发
开发语言·后端·golang
Channing Lewis2 小时前
flask实现重启后需要重新输入用户名而避免浏览器使用之前已经记录的用户名
后端·python·flask
Channing Lewis2 小时前
如何在 Flask 中实现用户认证?
后端·python·flask
酱学编程2 小时前
java中的单元测试的使用以及原理
java·单元测试·log4j
我的运维人生3 小时前
Java并发编程深度解析:从理论到实践
java·开发语言·python·运维开发·技术共享
一只爱吃“兔子”的“胡萝卜”3 小时前
2.Spring-AOP
java·后端·spring