编程笔记

命令和职责链模式的快速实现 commons chain

2019-03-08  本文已影响1人  老瓦在霸都

commons chain 是命令与职责链模式的经典实现 commons chain

基本概念

它有如下概念:

1) Context 上下文

Context 表示一个应用程序的状态, 它其实是一个 java.util.map 的标记接口, 上下文是类似一个信封, 包含了完成一个事务所需的属性, 换句话说, 上下文是一个包含成员属性值的有状态对象

2) Command 命令

一个命令代表一个工作单元, 它只有一个入口方法

public boolean execute(Context context)

命令对通过上下文对象传递给它的状态进行操作,但不保留它自己的状态。命令可以组装成一个链,这样就可以从离散的工作单元创建复杂的事务。如果命令返回true,则不应执行链中的其他命令。如果一个命令返回false,那么链中的其他命令(如果有的话)可能会执行。

3) Chain 职责链

chain实现了命令接口,因此chain可以与命令互换使用。应用程序不需要知道它是在调用链还是命令,所以您可以从一个重构到另一个。chain 可以根据需要套入其他链条。这一性质被称为Liskov替换原理。

4) Filter 过滤器

理想情况下,每个command 都是独立的。可在现实生活中,我们有时需要分配资源,并确保不管发生什么,资源都会被释放. Filter 过滤器是一种特殊的命令, 它增加了一个后处理方法 postProcess 。在命令返回之前,职责链 Chain 会调用其中任何 Filter 的 postProcess 方法。一个实现了 Filter 的命令可以通过 postProcess 方法安全地释放它分配的任何资源,即使这些资源是与其他命令共享的

5) Catalog 目录

许多应用程序使用“facades”和“factories”以及其他技术来避免将层与层耦合在一起。层与层之间需要交互,但通常我们不希望它们在类名级别交互。目录是一组命令或链的逻辑上的名称,客户端可以在不知道命令的类名的情况下执行这些命令。

举例如下

package com.cisco.yafan.demo;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;

import org.apache.commons.chain.impl.ChainBase;
import org.apache.commons.chain.impl.ContextBase;
import org.junit.Test;

import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;

@Slf4j
class IvrCommand implements Command {

    private String name;

    public IvrCommand(String name) {
        this.name = name;
    }

    @Override
    public boolean execute(Context context) throws Exception {
        log.info("execute: {} for {}", name, context.get("phoneNumber"));
        if("please input your password".equals(name)) {
            if("pass".equals(context.get("password"))) {
                context.put("balance", 10000);
            } else {
                log.info("your password is incorrect.");
                return true;
            }


        }

        return false;
    }
}

class IvrFlow extends ChainBase {

    public IvrFlow() {

        addCommand(new IvrCommand("welcome"));

        addCommand(new IvrCommand("please input account number"));

        addCommand(new IvrCommand("please input your password"));

        addCommand(new IvrCommand("your account balance is 10000"));

        addCommand(new IvrCommand("goodbye"));

    }
}

@Slf4j
public class CommonsChainTest {
    @Test
    public void testIvrFlowCorrectPassword() throws Exception {
        Context context = new ContextBase();
        context.put("phoneNumber" , "86-123456789");
        context.put("password" , "pass");

        IvrFlow ivrFlow = new IvrFlow();
        ivrFlow.execute(context);
        assertTrue(Integer.valueOf("10000").equals(context.get("balance")));
    }
    @Test
    public void testIvrFlowIncorrectPassword() throws Exception {
        Context context = new ContextBase();
        context.put("phoneNumber" , "86-123456789");
        context.put("password" , "abcd");

        IvrFlow ivrFlow = new IvrFlow();
        ivrFlow.execute(context);
        assertFalse(Integer.valueOf("10000").equals(context.get("balance")));
    }
}

结果输出如下

#testIvrFlowCorrectPassword
execute: welcome for 86-123456789
execute: please input account number for 86-123456789
execute: please input your password for 86-123456789
execute: your account balance is 10000 for 86-123456789
execute: goodbye for 86-123456789

#testIvrFlowIncorrectPassword
execute: welcome for 86-123456789
execute: please input account number for 86-123456789
execute: please input your password for 86-123456789
your password is incorrect.

上一篇下一篇

猜你喜欢

热点阅读