定义
使用场景
类型
优点
缺点
结合使用的设计模式
假设网购商城存在 普通用户、普通会员、高级会员三个角色,三个角色都需要进行下单操作,不同会员的的折扣不同,已经积分计算方式也不同。系统需要对不同的角色进行不同的操作。
在基于上述的背景,下面进行代码编写,并一步步演进。
package com.dsdj.behavioral.strategy;
/**
* TODO
*
* @author dsdj
* @version 1.0
* @className Demo1
* @date 2019/5/12 下午6:50
**/
public class Demo1 {
// 普通用户
private static final String ROLE_PTYH = "PTYH";
// 普通会员
private static final String ROLE_PTHY = "PTHY";
// 高级会员
private static final String ROLE_GJHY = "GJHY";
public static void main(String[] args) {
// 角色名称 普通用户
String roleName = ROLE_PTHY;
double price = 23.5;
if(ROLE_PTYH.equals(roleName)){
System.out.println("无折扣:"+price+"元");
System.out.println("积分增加5分.....");
} else if(ROLE_PTHY.equals(roleName)){
System.out.println("普通会员8折:"+price*0.8+"元");
System.out.println("积分增加10分....");
} else if (ROLE_GJHY.equals(roleName)){
System.out.println("高级会员5折:"+price*0.5+"元");
System.out.println("积分增加20分....");
}
}
}
输出
普通会员8折:18.8元
积分增加10分....
从实现方式一可以看到代码使用了大量的if…else…,同时代码扩展不易,如果增加了一个角色修改不易,并且一个方法中可能会造成大量代码,也不符合代码规范。
基于上述的不足,我们进一步演进代码。
通过分析,不同的角色的折扣和积分有不同的算法(策略),那么我们可以使用策略模式进行抽取包装。
定义各个策略以及策略的抽象
抽象类
package com.dsdj.behavioral.strategy;
public interface DiscountStrategy {
/**
* 折扣操作
*/
void discountOperate(Double price);
}
普通用户的折扣方式
package com.dsdj.behavioral.strategy;
public class PTYHDiscountStrategy implements DiscountStrategy{
public void discountOperate(Double price) {
System.out.println("无折扣:"+price+"元");
System.out.println("积分增加5分.....");
}
}
普通会员的折扣方式
package com.dsdj.behavioral.strategy;
public class PTHYDiscountStrategy implements DiscountStrategy{
public void discountOperate(Double price) {
System.out.println("普通会员8折:"+price*0.8+"元");
System.out.println("积分增加10分....");
}
}
高级会员的折扣方式
package com.dsdj.behavioral.strategy;
/**
* 高级会员
*
* @author dsdj
* @version 1.0
* @className PTHYDiscountStrategy
* @date 2019/5/12 下午7:13
**/
public class GJHYDiscountStrategy implements DiscountStrategy{
public void discountOperate(Double price) {
System.out.println("高级会员5折:"+price*0.5+"元");
System.out.println("积分增加20分....");
}
}
封装各策略
package com.dsdj.behavioral.strategy;
/**
* 包装类
**/
public class DiscountActivity {
private DiscountStrategy discountStrategy;
public DiscountActivity(DiscountStrategy discountStrategy){
this.discountStrategy = discountStrategy;
}
public void doDiscount(Double price){
discountStrategy.discountOperate(price);
}
}
测试类(高层模块)
package com.dsdj.behavioral.strategy;
/**
* TODO
*
* @author dsdj
* @version 1.0
* @className Demo1
* @date 2019/5/12 下午6:50
**/
public class Demo1 {
// 普通用户
private static final String ROLE_PTYH = "PTYH";
// 普通会员
private static final String ROLE_PTHY = "PTHY";
// 高级会员
private static final String ROLE_GJHY = "GJHY";
public static void main(String[] args) {
// 角色名称 普通用户
String roleName = ROLE_PTHY;
double price = 23.5;
DiscountActivity discountActivity = null;
if(ROLE_PTYH.equals(roleName)){
discountActivity = new DiscountActivity( new PTYHDiscountStrategy());
} else if(ROLE_PTHY.equals(roleName)){
discountActivity = new DiscountActivity(new PTHYDiscountStrategy());
} else if (ROLE_GJHY.equals(roleName)){
discountActivity = new DiscountActivity( new GJHYDiscountStrategy());
}
discountActivity.doDiscount(price);
}
}
总结:在实现方式二中,我们对策略进行抽取并封装了,高层模块屏蔽了对具体细节的实现。但是代码中还是存在大量if…else…
针对上述的问题,下面我们结合工厂模式,对代码进一步改造
定义一个策略工厂
package com.dsdj.behavioral.strategy;
import java.util.HashMap;
import java.util.Map;
/**
* 策略工厂
**/
public class DiscountStrategyFactory {
// 普通用户
public static final String ROLE_PTYH = "PTYH";
// 普通会员
public static final String ROLE_PTHY = "PTHY";
// 高级会员
public static final String ROLE_GJHY = "GJHY";
private static final Map<String,DiscountStrategy> map = new HashMap();
static {
map.put(ROLE_PTYH,new PTYHDiscountStrategy());
map.put(ROLE_PTHY,new PTHYDiscountStrategy());
map.put(ROLE_GJHY,new GJHYDiscountStrategy());
}
private DiscountStrategyFactory(){
}
public static DiscountStrategy getDiscountStrategy(String roleName){
DiscountStrategy discountStrategy = map.get(roleName);
return discountStrategy == null? null:discountStrategy;
}
}
测试类
package com.dsdj.behavioral.strategy;
public class Demo1 {
public static void main(String[] args) {
// 角色名称 普通用户
String roleName = DiscountStrategyFactory.ROLE_GJHY;
double price = 23.5;
DiscountActivity discountActivity = new DiscountActivity(DiscountStrategyFactory.getDiscountStrategy(roleName));
discountActivity.doDiscount(price);
}
}
总结:结合工厂模式使用之后,代码的可读性就增加了,也复合开闭原则,对增加了代码的扩展性。