设计模式(行为型设计模式------策略模式)
策略模式
基本定义
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
模式结构
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
优点
多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。
策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
缺点
客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
策略模式造成很多的策略类。
使用场景
一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。
一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。
系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。