设计模式(行为型设计模式——策略模式)

设计模式(行为型设计模式------策略模式)

策略模式

基本定义

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

模式结构

  • Strategy 抽象策略类:所有策略类的父类,为所支持的策略算法声明了抽象方法。

  • ConcreteStrategy 具体策略类:实现了在抽象策略类中声明的方法。

  • Context 环境类:负责使用算法策略,其中维持了一个抽象策略类的引用实例。

代码实现

Strategy 抽象策略类
java 复制代码
public abstract class Discount {
  //计算折扣抽象方法
    abstract double discountPrice(Double originalPrice);
}
ConcreteStrategy 具体策略类
java 复制代码
//首单五折
public class FirstOrderDiscount extends Discount{

    double discount = 0.5; //五折

    @Override
    public double discountPrice(Double originalPrice) {
        return originalPrice * discount;
    }
}
//会员七折
public class MemberDiscount extends Discount{

    double discount = 0.7; //七折

    @Override
    public double discountPrice(Double originalPrice) {
        return originalPrice * discount;
    }
}
//前100名下单八折
public class Top100Discount extends Discount{

    double discount = 0.8; //八折

    @Override
    public double discountPrice(Double originalPrice) {
        return originalPrice * discount;
    }
}
Context 环境类
java 复制代码
public class Context {
  //存储折扣算法
    public static Map<String, Discount> strategyMap = new ConcurrentHashMap<>();

    static {
        for (DiscountType discountType: DiscountType.values()){
            try {
                //基于反射创建全部折扣算法类
                strategyMap.put(discountType.toString(), (Discount) Class.forName(discountType.getClassName()).newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    //计算折扣
    public static double discountPrice(String type, Double originalPrice){
        return strategyMap.get(type).discountPrice(originalPrice);
    }

    //计算折扣
    public static double discountPrice(DiscountType type, Double originalPrice){
        return discountPrice(type.toString(), originalPrice);
    }
}

//折扣枚举类
public enum DiscountType {

    MEMBER("会员折扣", "com.yanyuan.gof.behavior.strategy.v2.MemberDiscount"),
    FIRST_ORDER("首次下单", "com.yanyuan.gof.behavior.strategy.v2.FirstOrderDiscount"),
    TOP100("前100名下单", "com.yanyuan.gof.behavior.strategy.v2.Top100Discount");

    private String name;

    private String className;

    DiscountType(String name, String className) {
        this.name = name;
        this.className = className;
    }

    public String getName() {
        return name;
    }

    public String getClassName() {
        return className;
    }
}
测试类
java 复制代码
@Slf4j
public class Test {
    public static void main(String[] args) {
        Double originalPrice = 200d;
        //首次下单
        DiscountType type = DiscountType.FIRST_ORDER;
        double price = Context.discountPrice(type, originalPrice);
        log.info("尊敬的用户: 您所预定的游乐园门票使用 [{}] 折扣, 原价{} RMB, 折后价格 {} RMB ",  type.getName(), originalPrice, price);

        //会员折扣
        type = DiscountType.MEMBER;
        price = Context.discountPrice(type, originalPrice);
        log.info("尊敬的用户: 您所预定的游乐园门票使用 [{}] 折扣, 原价{} RMB, 折后价格 {} RMB ",  type.getName(), originalPrice, price);
    }
}
输出结果

尊敬的用户: 您所预定的游乐园门票使用 [首次下单] 折扣, 原价200.0 RMB, 折后价格 100.0 RMB 尊敬的用户:

您所预定的游乐园门票使用 [会员折扣] 折扣, 原价200.0 RMB, 折后价格 140.0 RMB

优点

  • 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。

  • 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。

  • 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。

  • 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。

  • 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。

缺点

  • 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。

  • 策略模式造成很多的策略类。

使用场景

  • 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。

  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。

  • 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。

相关推荐
菜鸟一枚在这19 分钟前
深度解析建造者模式:复杂对象构建的优雅之道
java·开发语言·算法
gyeolhada36 分钟前
2025蓝桥杯JAVA编程题练习Day5
java·数据结构·算法·蓝桥杯
菜鸟一枚在这39 分钟前
深入理解设计模式之代理模式
java·设计模式·代理模式
小天努力学java1 小时前
【面试系列】Java开发--AI常见面试题
java·人工智能·面试
river661 小时前
java开发——为什么要使用动态代理?
java
Zayn~1 小时前
JVM系列--虚拟机类加载机制
java
m0_748248021 小时前
Redis使用手册
java
CoderCodingNo1 小时前
【GESP】C++二级真题 luogu-b3924, [GESP202312 二级] 小杨的H字矩阵
java·c++·矩阵
2501_903238652 小时前
Spring MVC中环境配置的实战应用
java·spring·mvc·个人开发
程序员侠客行2 小时前
Spring事务原理详解 三
java·后端·spring·架构