设计模式,策略模式

策略模式概述

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

  • 环境(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起到工厂的作用,能让业务代码更为简洁,也更易于理解和使用。比起普通的策略模式,耦合度更低,封装性更强。

相关推荐
令狐前生12 分钟前
Intellij IDEA 2025 破解安装
java·ide·intellij-idea
数聚天成DeepSData40 分钟前
数聚天成 DeepSData 数据价值落地实战指南
java·maven·devops
techdashen41 分钟前
Go设计取舍之四: map不变时能否并发修改不同value
开发语言·后端·golang
小小小米粒1 小时前
阿姆达尔定律(Amdahl‘s Law)
java·开发语言
知彼解己1 小时前
Java 版本演进
java·开发语言·spring boot
极客先躯1 小时前
高级java每日一道面试题-2026年05月11日-实战篇[Docker]-如何容器化金融产品推荐系统?
java·运维·docker·容器·金融·高级面试·金融产品推荐系统
朱容zr3331331 小时前
为什么推荐使用自增主键?使用UUID作为主键的优缺点是什么?
java·运维·数据库·后端·mysql·面试·性能优化
用户608186527902 小时前
一文吃透 Avalonia 布局容器|Grid 到 UniformGrid 核心用法 + 语法糖实战
后端
Ai拆代码的曹操2 小时前
Dubbo 线程池爆满排坑:Linux 用户线程数限制,一个容易被忽略的根因
后端·源码阅读
知彼解己2 小时前
Eclipse Temurin:企业级 Java JDK 发行版的最佳实践
java·ide·eclipse