策略模式的UML

个人理解 :首先可以将策略算法抽象为一个接口或者是一个抽象类,根据上下文的环境实现具体的策略实现类
实例一
超市消费:
用户根据自己的等级,可以享受不同的打折优惠
normal用户: 不打折
vip用户:打九折
普通的实现方法
@Test
public void initPlan() {
// 可以理解为上下文中传来的值
String level = "normal";
switch (level) {
case "normal":
// todo 不打折
break;
case "vip":
// todo 打九折
break;
case "super_vip":
// todo 打八折
break;
}
}
使用策略模式+spring的实现
定义会员的枚举
public enum MemLevel { NORMAl(0, "普通会员"), VIP(1, "普通会员"); private Integer level; private String desc; MemLevel(Integer level, String desc) { this.level = level; this.desc = desc; } public Integer getLevel() { return level; } }首先抽象出会员计算的策略接口
public interface IDisCount { /** * 获取当前策略的类型 * @return */ MemLevel getType(); /** * 具体的打折操作 */ void operation(); }完成具体的策略类
/** * 普通顾客 */ @Component public class NormalDisCount implements IDisCount { @Override public MemLevel getType() { return MemLevel.NORMAl; } @Override public void operation() { // 逻辑操作 System.out.println("原价"); } }/** * VIP 顾客 */ @Component public class VipDiscount implements IDisCount { @Override public MemLevel getType() { return MemLevel.VIP; } @Override public void operation() { // 逻辑操作 System.out.println("九折"); } }编写服务层
@Service public class ShoppingService implements ApplicationContextAware { Map<Integer, IDisCount> strategy; /** * 根据总共消费的金额来判断打折的方式 * @param */ public void shopping(Integer level) { // 获取相应的策略 IDisCount iDisCount = strategy.get(level); // 执行策略操作 iDisCount.operation(); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // 获取ioc容器中的所有IDisCount组件, 加入到 Map<MemLevel, IDisCount> strategy; Map<String, IDisCount> iDisCountMap = applicationContext.getBeansOfType(IDisCount.class); HashMap<Integer, IDisCount> map = new HashMap<>(); iDisCountMap.forEach((k, v) -> map.put(v.getType().getLevel(), v)); this.strategy = map; } }测试
public class StrategyTest { AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(Config.class); @Test public void test() { // 会员等级 Integer memLevel = 1; // 从ioc容器中获取ShoppingService ShoppingService shoppingService = ioc.getBean(ShoppingService.class); shoppingService.shopping(1); } }
从以上两种方案可以看出,使用设计模式明显的加大了代码量,那为什么又要使用
如果我们要增加一个SuperVip用户打八折的方案
如果是第一种方案则需要加一个case语句,看似没有多大的问题
但是随着需求的增加,代码量会异常的臃肿,你在修改的过程中不可能保证不误修改原来的代码
所以我们选择策略模式的方案
我们不需要修改以前的代码只需要添加一个具体的策略类和修改一下枚举类型
public enum MemLevel {
NORMAl(0, "普通会员"),
VIP(1, "普通会员"),
SUPER_VIP(2, "超级会员");
private Integer level;
private String desc;
MemLevel(Integer level, String desc) {
this.level = level;
this.desc = desc;
}
public Integer getLevel() {
return level;
}
}
/**
* VIP 顾客
*/
@Component
public class SuperVipDiscount implements IDisCount {
@Override
public MemLevel getType() {
return MemLevel.SUPER_VIP;
}
@Override
public void operation() {
// 逻辑操作
System.out.println("八折");
}
}
其他的情况
如果出现在某个范围使用的一个策略的方式该怎么处理
现在将消费的等级修改为消费的总金额范围
我们只需要将接口中的getType() (获取类型) 改为一个具体的范围即可
/**
* 打折接口
*/
public interface IDisCount {
/**
* 用来判断范围
* @param value
* @return
*/
Boolean isMatch(int value);
/**
* 具体的打着操作
*/
void operation();
}
具体的实现
/**
* 普通顾客
*/
@Component
public class NormalDisCount implements IDisCount{
@Override
public Boolean isMatch(int value) {
return value > 0 && value < 100;
}
@Override
public void operation() {
System.out.println("原价");
}
}
Service层
@Service
public class ShoppingService implements ApplicationContextAware {
List<IDisCount> strategy;
/**
* 根据总共消费的金额来判断打折的方式
* @param price
*/
public void shopping(int price) {
// 获取相应的策略
IDisCount iDisCount = strategy.stream().
filter(strategy -> strategy.isMatch(price))
.findFirst()
.get();
// 执行策略操作
iDisCount.operation();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// 获取ioc容器中的所有IDisCount组件, 加入到 List<IDisCount> strategy;
Map<String, IDisCount> beansOfType = applicationContext.getBeansOfType(IDisCount.class);
List<IDisCount> iDisCounts = new ArrayList<>();
beansOfType.forEach((k, v) -> {
iDisCounts.add(v);
});
this.strategy = iDisCounts;
}
}
可以看出使用java8 的新特性可以轻松的解决
如果 策略处理的参数类型和返回值类型不同
可以使用模板方法设计模式
使用抽象类替代接口,继承该抽象类, 各个具体的实现只需要重写抽象类中某个方法即可
版权声明:本文为qq_46054356原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。