阅读 602

再见 if else —— 策略模式的常见案例

再见 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 本身无罪,但是难以维护的代码,一个方法成百上千可能会让下一个人崩溃。

文章分类
后端
文章标签