Разберитесь с моделью цепочки ответственности в одной статье

Шаблоны проектирования

определение

Шаблон цепочки ответственности заключается в создании нескольких объектов, которые обрабатывают запросы.Эти объекты образуют цепочку в определенном порядке.(Как и в связанном списке, есть указатель для поиска преемника) Предыдущий объект сохраняет ссылку на экземпляр следующего объекта. , который можно найти в соседнем объекте An, запрос начинается с головы и передается по этой цепочке, тот, кто может его обработать, обрабатывается сразу, запрос заканчивается, до конца цепочки.Так же, как и разрешение компании на отпуск, иногда его должен одобрить начальник отдела, а иногда — отдел кадров. Например, фильтр в структуре структуры также является применением шаблона цепочки ответственности.
Обработка заказов с разными приоритетами в системе ERP может использовать модель цепочки ответственности. Например, заказы делятся на предпродажные предварительные заказы, обычные заказы и срочные заказы на доставку, создаются разные обработчики для обработки разных типов заказов, а затем организуются эти обработчики в цепочку ответственности в соответствии с приоритетом, и все заказы проходят через эту ответственность. chain, в зависимости от уровня ордера, только процессор соответствующего уровня может обрабатывать ордер соответствующего уровня, что равносильно тому, есть ли разрешение.

UML

Шаблон цепочки ответственности включает в себя две роли:
Роль абстрактного обработчика (Handler): содержит ссылку на объект следующего обработчика, определяет интерфейс для обработки запросов и предоставляет метод для установки следующего обработчика.
ConcreteHandler: реализует или наследует роль абстрактного обработчика.

Цепочка ответственности за заказы

Как было сказано выше, для обработки трех заказов с разными приоритетами нам необходимо определить хотя бы одного абстрактного обработчика, а затем определить трех конкретных обработчиков, и сформировать цепочку ответственности этих трех обработчиков по приоритету, а затем уже в бизнесе логика, передать заказ в Цепочку Ответственности для обработки.

абстрактный процессор

/**
 * 抽象处理器角色
 */
public abstract class Handler {

    private Handler nextHandler;

    private Integer priority;

    public Handler(Integer priority) {
        this.priority = priority;
    }

    public void setHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /**
     * 处理订单请求的传递,如果是当前级别则调用solveOrder()方法处理,否则传递给上一级处理。
     * @param order
     */
    public final void handleOrder(Order order) {
        if (order == null || order.getOrderId() == null) {
            throw new RuntimeException("订单信息为空,无法处理");
        }
        if (order.getPriority() == null) {
            throw new IllegalArgumentException("订单"+order.getOrderId()+"没有设置处理级别");
        }
        if (order.getPriority().equals(this.priority)) {
            this.solveOrder(order);
        } else {
            if (this.nextHandler != null) {
                System.out.println(this.getClass().getName()+"无法处理订单"+order.getOrderId()+",传递给高一级的handler处理");
                nextHandler.handleOrder(order);
            } else {
                throw new RuntimeException("没有Handler能够处理当前等级的订单");
            }
        }
    }

    /**
     * 定义处理订单的方法,由子类实现,处理不同等级的订单
     */
    public abstract void solveOrder(Order order);
}
public class Order {

    //订单id
    private Long orderId;

    //订单优先级
    private Integer priority;

    public Long getOrderId() {
        return orderId;
    }

    public void setOrderId(Long orderId) {
        this.orderId = orderId;
    }

    public Integer getPriority() {
        return priority;
    }

    public void setPriority(Integer priority) {
        this.priority = priority;
    }
}

Предположим, заказ содержит идентификатор заказа и приоритет заказа.
В абстрактном процессоре мы определяем следующий процессор nextHandler и определяем метод set для его установки, а затем определяем унифицированный метод для обработки заказов, который является записью при вызове подкласса для проверки достоверности информации о заказе. судить о приоритете заказа, может ли его обработать текущий процессор, если он не может быть обработан, он будет передан следующему процессору, а если следующего процессора нет, будет сгенерировано исключение.

конкретный процессор

/**
 * 定义一个Map容器,保存所有订单处理器
 */
public class OrderHandlerMap {

    public static Map<Integer, Handler> map = new HashMap<>();

}
/**
 * 预售订单的处理器,预售订单的优先级最低
 */
@Component
public class PreSellOrderHandler extends Handler implements InitializingBean{

    /**
     * 设置能够处理的订单优先级=1
     */
    PreSellOrderHandler() {
        super(1);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"开始处理订单"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() {
        OrderHandlerMap.map.put(1,this);
    }
}

/**
 * 正常订单的处理器,设置优先级为2
 */
@Component
public class NormalOrderHandler extends Handler implements InitializingBean{

    /**
     * 设置能够处理的订单优先级=2
     */
    NormalOrderHandler() {
        super(2);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"开始处理订单"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() {
        OrderHandlerMap.map.put(2, this);
    }
}

/**
 * 紧急发货订单的处理器,设置优先级最高=3
 */
@Component
public class UrgentOrderHandler extends Handler implements InitializingBean{

    /**
     * 设置能够处理的订单优先级=3
     */
    UrgentOrderHandler() {
        super(3);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"开始处理订单"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() {
        OrderHandlerMap.map.put(3,this);
    }
}

Определены три обработчика заказов с разными приоритетами, а объект обработчика создается и помещается в контейнер Map при запуске контейнера spring.

класс обработки заказов

Предположим, сейчас заказ, как вы относитесь к ответственной цепочке?

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class)// 指定spring-boot的启动类
public class OrderHandlerTest1 {

    @Test
    public void test() {
        Map<Integer, Handler> handlerMap = OrderHandlerMap.map;
        if (handlerMap.isEmpty()) {
            throw new RuntimeException("spring中没有注册任何处理器");
        }
        //获取最低优先级的处理器
        Handler handler = null;
        for (Map.Entry<Integer,Handler> entry : handlerMap.entrySet()) {
            handler = entry.getValue();
            if (handler !=null) {
                break;
            }
        }
        //测试预售提前单的责任链处理
        Order preSellOrder = new Order();
        preSellOrder.setOrderId(123L);
        preSellOrder.setPriority(1);
        handler.handleOrder(preSellOrder);

        //测试正常单的责任链处理
        Order normalOrder = new Order();
        normalOrder.setOrderId(456L);
        normalOrder.setPriority(2);
        handler.handleOrder(normalOrder);

        //测试紧急发货订单的责任链处理
        Order urgentOrder = new Order();
        urgentOrder.setOrderId(789L);
        urgentOrder.setPriority(3);
        handler.handleOrder(urgentOrder);

        //测试未知等级的订单能否处理
        Order unknownOrder = new Order();
        unknownOrder.setOrderId(111L);
        unknownOrder.setPriority(9);
        handler.handleOrder(unknownOrder);
    }

    @Before
    public void before(){
        Map<Integer, Handler> handlerMap = OrderHandlerMap.map;
        if (handlerMap.isEmpty()) {
            throw new RuntimeException("spring中没有注册任何处理器");
        }
        //先按照优先级排个序
        List<Map.Entry<Integer,Handler>> list = new ArrayList<>(handlerMap.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<Integer, Handler>>() {
            @Override
            public int compare(Map.Entry<Integer, Handler> o1, Map.Entry<Integer, Handler> o2) {
                return o1.getKey().compareTo(o2.getKey());
            }
        });
        List<Integer> keys = new ArrayList<>(handlerMap.keySet());
        Collections.sort(keys);
        //设置处理器的更高一级的处理器,keys已经是按照优先级排好序的
        for (int i=0; i<keys.size(); i++) {
            Integer key = keys.get(i);
            Handler handler = handlerMap.get(key);
            if (i < keys.size()-1) {
                Integer nextKey = keys.get(i + 1);
                if (nextKey != null) {
                    Handler nextHandler = handlerMap.get(nextKey);
                    handler.setHandler(nextHandler);
                }
            }
        }
    }
}

Перед тестированием мы сначала организуем процессоры на карте в цепочку ответственности процессоров, упорядоченную по приоритету, и нам нужно установить, кто будет следующим процессором текущего процессора. Затем в тестовом методе создаются четыре заказа с разными приоритетами, и все они передаются первому обработчику цепочки ответственности за обработку, но реально обработать заказ может только обработчик соответствующего уровня. Текущий результат следующий: первый процессор может обработать заказ 123, второй процессор может обработать заказ 456, а третий процессор может обработать заказ 789. Поскольку уровень заказа 111 неизвестен и ни один процессор не может его обработать, возникает ошибка. сообщил.