责任链,规则树,与策略模式

278 阅读2分钟

责任链,规则树,与策略模式

业务中通常会涉及到很长的if,这个时候我们可以采用适当的设计模式优化代码。

首先是责任链,这是一个链表结构。

package logicChain;

public abstract class LogicChainNode<T> implements processable<T>{
    private LogicChainNode<T> next;

    public LogicChainNode<T> setNext(LogicChainNode<T> next) {
        return this.next = next;
    }
    public LogicChainNode<T> getNext(){
        return next;
    }
}

在抽象类节点中定义了下一个节点的引用,并要求子类实现该节点的具体执行逻辑。该抽象类中没有定义具体需要依赖的数据。如果我们需要一个输出日志的责任链,那我们可以将泛型T指定为LogInfo及其子类。

package logicChain.impl.log;

public class Level1LogNode<T extends LogInfo> extends LogicChainNode<T>{

    @Override
    public void process(T t) {
        if (t.getLevel() == 1){
            System.out.println("日志等级:" + t.getLevel());
            System.out.println("日志内容:" + t.getContent());
            //将日志内容写入level1的日志文件,或是发送到其他地方
        }else {
            if (getNext() != null){
                getNext().process(t);
            }
        }
    }
}


package logicChain.impl.log;

public class Level2LogNode<T extends LogInfo> extends LogicChainNode<T>{

    @Override
    public void process(T t) {
        if (t.getLevel() == 2){           
            System.out.println("日志等级:" + t.getLevel());
            System.out.println("日志内容:" + t.getContent());
            //将日志内容写入level2的日志文件,或是发送到其他地方
        }else {
            if (getNext() != null){
                getNext().process(t);
            }
        }
    }
}

level1和level2的日志发送,写入逻辑可能并不相同,两个类并不冗余。

最后我们需要将责任链节点组合起来。我们可以使用静态工程+单例模式

package logicChain.factory;

import logicChain.impl.log.Level1LogNode;
import logicChain.impl.log.Level2LogNode;
import logicChain.impl.log.LogChain;
import logicChain.impl.log.LogInfo;

public class LogicChainFactory {
    private static volatile LogChain<LogInfo> logChain;
    public static LogChain<LogInfo> getLogChain() {
        // lazy init,双检锁
        if (logChain == null) {
            synchronized (LogChain.class) {
                if (logChain == null) {
                    logChain = new LogChain<>();
                    logChain.setNext(new Level1LogNode<>())
                            .setNext(new Level2LogNode<>());
                }
            }
        }
        return logChain;
    }
}

可见,责任链实际上是一个链表,每个节点有自己的执行逻辑。在这个执行逻辑中,通常会有条件判断并调用下一个节点的执行逻辑。以此完成链式调用。

那么,既然已经是链表了,那如果我们在每一个节点后挂载两个或更多节点,就变成了规则树。在一个节点中,执行逻辑将会判断条件并根据结果选择调用哪一个子节点的执行逻辑。实现十分类似,不再赘述。

策略模式十分接近于Spring中单Service接口的多实现。举个例子:有一个支付接口,我们可以为它实现微信支付,或是支付宝支付,等等。策略模式多用于只需少量判断的场景。先建立一个策略接口。

// 支付策略接口
public interface PaymentStrategy {
    void pay(int amount);
}

然后实现它

package stratagy.impl;

import stratagy.PaymentStrategy;

public class WeChatPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        //使用微信支付
        System.out.println("微信支付了"+amount+"元");
    }
}

创建上下文类,然后在这个类中持有对策略的引用,随后将支付方法委托给这个策略的支付方法

package stratagy.content;

import stratagy.PaymentStrategy;

public class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    private int amount;
    public void setPaymentStrategy(PaymentStrategy paymentStrategy){
        this.paymentStrategy = paymentStrategy;
    }
    public void doPayment(int amount){
        paymentStrategy.pay(amount);
    }
}

这样依赖注入的方式同样可以用IOC容器实现,也就变成了单个Service接口多实现的例子。