设计模式之策略模式
策略模式(Strategy Pattern)是一种简单常用的设计模式,也叫做政策模式(Policy Pattern),定义一组算法,将每个算法封装起来,并且使他们相互转换。
结构组成
- Context封装角色
它也叫做上下文角色,起承上启下的封装作用,屏蔽高层模块对策略,算法的直接访问,封装可能存在的变化。
- Strategy抽象策略角色
策略、算法的抽象,通常为接口,定义每个策略或算法必有的方法和属性。
- 具体策略(ConcreteStrategy)角色
实现抽象策略中的具体操作,该类含有具体的算法。
示例(改编自网红代码)
以下代码改编自业界盛传的某超级大厂的网红代码。
public class VIPCenter {
/**
* user共同属性
*/
class BaseUser {
//do something
}
/**
* 穷逼user,送的那种
*/
class SlumDogVIP extends BaseUser {
//do something
}
/**
* 正儿八经买vip的user
*/
class RealVIP extends BaseUser {
//do something
}
/**
* 实际业务处理
*/
public void serviceVIP(BaseUser user) {
if (user instanceof SlumDogVIP) {
//穷逼VIP,活动送的那种
System.out.println("穷逼");
} else {
//正儿八经的VIP
System.out.println("不穷");
}
}
}
对于这段代码,业务逻辑集中在一起,当出现新的用户类型时, 比如,增加一个SuperVIP用户类型,这就需要直接去修改服务方法代码实现(在serviceVIP方法里面在加else if),违反了开关原则(Open-Close)(对新增开放,对修改关闭)。这可能会意外影响不相关的某个用户类型逻辑。
改进
public class VIPCenterImprove {
//抽象策略
private ServiceHandler serviceHandler;
//构造函数设置具体策略
public VIPCenterImprove(ServiceHandler serviceHandler) {
this.serviceHandler = serviceHandler;
}
/**
* Context封装角色
* 封装后的策略方法
*/
public void serviceVIP(BaseUser user) {
this.serviceHandler.service(user);
}
/*------------------------------------------------*/
/**
* user共同属性
*/
static class BaseUser {
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
//do something
}
/*------------------------------------------------*/
/**
* 穷逼user,送的那种
*/
static class SlumDogVIP extends BaseUser {
//do something
}
/*------------------------------------------------*/
/**
* 正儿八经买vip的user
*/
static class RealVIP extends BaseUser {
//do something
}
/*------------------------------------------------*/
/**
* 可以为所欲为的VIP
*/
static class SuperVip extends BaseUser{
}
/*------------------------------------------------*/
/**
* Strategy抽象策略角色
*/
interface ServiceHandler{
void service(BaseUser user);
}
/*------------------------------------------------*/
/**
* 具体策略(ConcreteStrategy)角色
* 处理穷逼VIP
*/
static class SlumDogVIPServiceHandler implements ServiceHandler{
@Override
public void service(BaseUser user){
System.out.println("该用户是:" + user.getDesc());
System.out.println("穷逼");
}
}
/*------------------------------------------------*/
/**
* 具体策略(ConcreteStrategy)角色
* 处理正常的VIP
*/
static class RealVIPServiceHandler implements ServiceHandler{
@Override
public void service(BaseUser user) {
System.out.println("该用户是:" + user.getDesc());
System.out.println("正常人");
}
}
/*------------------------------------------------*/
/**
* 具体策略(ConcreteStrategy)角色
* 处理可以为所欲为的VIP
*/
static class SuperVipServiceHandler implements ServiceHandler{
@Override
public void service(BaseUser user) {
System.out.println("该用户是:" + user.getDesc());
System.out.println("可以为所欲为的VIP");
}
}
/*------------------------------------------------*/
public static void main(String[] args) {
//声明一个具体的策略
ServiceHandler serviceHandler1 = new SlumDogVIPServiceHandler();
BaseUser user1 = new SlumDogVIP();
user1.setDesc("穷逼");
//声明一个上下文对象
VIPCenterImprove vipCenter1 = new VIPCenterImprove(serviceHandler1);
//执行封装后的方法
vipCenter1.serviceVIP(user1);
//第二种策略
serviceHandler1 = new RealVIPServiceHandler();
user1 = new RealVIP();
user1.setDesc("正常");
//只需“注入”策略实现类(RealVIPServiceHandler)
vipCenter1 = new VIPCenterImprove(serviceHandler1);
vipCenter1.serviceVIP(user1);
//第三种策略
/*serviceHandler1 = new SuperVipServiceHandler();
user1 = new SuperVip();
user1.setDesc("富豪");
vipCenter1 = new VIPCenterImprove(serviceHandler1);
vipCenter1.serviceVIP(user1);*/
}
上面的示例,将不同的对象分类的服务方法进行抽象,把业务逻辑的紧耦合关系拆开,实现代码隔离方便扩展。如果以后再出现新的用户类型,只需要重新实现一个策略接口ServiceHandler即可,然后将其注入到VIPCenterImprove(Context),这样比直接在serviceVIP方法里面加else if 优雅!
优缺点
优点
- 算法自由切换,只需要将具体的实现类“注入”到Context中即可
- 避免多重条件判断
- 扩展性良好
缺点:
- 策略类数量增多
- 所有的策略类必须都需要对外暴露。
使用场景:
- 多个类只有在算法或行为上的不同
- 算法需要自由切换