再见 if else —— 策略模式的常见案例
什么是策略模式?借用一下大话设计模式中的一句话 策略模式它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
这是本例中的一个产品类,只有一个属性type用以标记产品的类型
package StrategyPattern;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Product {
private ProductType type;
}
enum ProductType {
T1, T2, T3
}
复制代码
1) 一段充斥着if else 的代码
package StrategyPattern;
public class GoodByeIfElse {
public static void main(String[] args) {
run();
}
public static void run(){
Product p1 = new Product(ProductType.T1);
Product p2 = new Product(ProductType.T2);
processProduct(p1);
processProduct(p2);
}
public static void processProduct(Product p) {
if (p.getType() == ProductType.T1) {
System.out.println("type 1 process");
} else if (p.getType() == ProductType.T2) {
System.out.println("type 2 process");
}
}
}
复制代码
这段代码很简单,分别新建了T1 T2 几种type的产品并交由processProduct进行加工。这段代码本身从逻辑和程序执行上完全没有错误,但是为什么说这段充斥着 if-else 的代码是一段很不好的代码?一个就直接的原因就是加入其他ProductType或者某个ProductType的处理逻辑发生改变(不再只是一个println),就都需要改动processProduct,当需要进行判断的if else 极其多的时候 这个方法会大到无法想象。
摘自《菜鸟教程》的一句话:在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
什么意思?本质上processProduct这个方法是对各种Product进行加工,而加工可以理解为就是一堆 行为或者算法。
2) 引入了策略模式后的代码
先看引入策略模式后的代码结构:
// 处理器基类
public interface Processor {
Product process(Product p);
}
// 处理器的分发器
// 无论是Dispatcher或者是各个Processor 都应以单例最佳 但是单例不是这里的目的 就不再引入其他东西了
class ProcessorDispatcher {
private final HashMap<ProductType, Processor> map;
public ProcessorDispatcher() {
map = new HashMap<>();
map.put(ProductType.T1, new Type1Processor());
map.put(ProductType.T2, new Type2Processor());
}
public Processor dispatch(ProductType type) {
return map.get(type);
}
}
// 分别处理不同的type
class Type1Processor implements Processor {
@Override
public Product process(Product p) {
// process ing...
System.out.println("process type 1");
return p;
}
}
class Type2Processor implements Processor {
@Override
public Product process(Product p) {
// process ing...
System.out.println("process type 2");
return p;
}
}
复制代码
分别定义了 接口Processor ,两个实现类Type1Processor Type2Processor,以及ProcessorDispatcher 处理器分发类。
基于这个结构 调用方需要记性process时,只需要通过ProcessorDispatcher的dispatch方法来决定此时返回的具体Processor实现类,而不同Processor的改动也不会影响到其他代码,只需关注Processor自身即可。看看修改后的调用程序。
public static void main(String[] args) {
run();
}
public static void run(){
Product p1 = new Product(ProductType.T1);
Product p2 = new Product(ProductType.T2);
processProduct(p1);
processProduct(p2);
processProductStrategyPattern(p1);
processProductStrategyPattern(p2);
}
public static void processProduct(Product p) {
if (p.getType() == ProductType.T1) {
System.out.println("type 1 process");
} else if (p.getType() == ProductType.T2) {
System.out.println("type 2 process");
}
}
public static void processProductStrategyPattern(Product p ){
ProcessorDispatcher dispatcher = new ProcessorDispatcher();
dispatcher.dispatch(p.getType()).process(p);
}
复制代码
同一个行为具有多个不同表现形式或形态的能力,这里也正是体现了多态的魅力,调用方使用接口,面向接口开发,而不用全关心里面的具体实现。
if else 本身无罪,但是难以维护的代码,一个方法成百上千可能会让下一个人崩溃。