Шаблон цепочки ответственности и шаблон цепочки ответственности лямбда-рефакторинга

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

1. Концепция и предыстория

Схема цепочки ответственности: Шаблон цепочки ответственности — это общая схема создания последовательности объектов обработки (например, последовательности операций). Объекту-обработчику может потребоваться выполнить некоторую работу, передать результат другому объекту, который затем выполняет некоторую работу, прежде чем передать его следующему объекту-обработчику, и так далее.

Короче говоря, объект, который необходимо обработать, должен быть обработан в несколько шагов, чтобы сформировать цепочку.После обработки одного шага обработка переходит к следующему шагу.

Код, задействованный в этой статье, находится на github, нажмитеСсылка на сайтВы можете просмотреть исходный код.

В этой статье паттерн цепочки ответственности будет реализован двумя способами: второй — в виде лямбда-выражения и в виде поведения параметра.

Сценарии, используемые в этой статье, следующие:: Чтобы обработать письмо, сначала обработайте заголовок письма, затем проверьте написание письма на наличие ошибок, исправьте неправильные слова, если они есть, и, наконец, обработайте конец письма. Обработка письма таким образом образует цепочку: сначала обработка..., затем обработка... и, наконец, обработка....

2. Модель цепочки ответственности

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

uml图

  • Абстрактный класс Handler, то есть абстрактный класс обработки, содержит поле, которое является преемником абстрактного обработчика, а также метод setSuccessor, который используется для установки следующего обработчика, то есть после этого шага/цепочки. узел обрабатывается, он передается следующему обработчику для продолжения обработки. Абстрактный метод handleWork обеспечивает разные этапы обработки и различную логику обработки.Метод handle здесь тоже играет много ролей, образуя цепочку.После handleWork этого узла цепочки он определяет, есть ли у него следующий обработчик.Некоторые Если да, то следующий обработчик продолжает работу handle->handleWork до конца процесса, а обработчика нет.
public abstract class Handler {

    protected Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    abstract protected String handleWork(String input);

    public String handle(String input) {
        //本节点处理完之后返回下一节点
        String nextNode = handleWork(input);
        if (successor != null) {
            return successor.handle(nextNode);
        }
        return nextNode;
    }
}
  • Класс AddHeaderHandler, обработчик заголовка письма
public class AddHeaderHandler extends Handler{
    @Override
    protected String handleWork(String input) {
        return  "From Raoul, Mario and Alan: " + input;
    }
}
  • Класс CheckSpellHandler, проверяет правописание букв
public class CheckSpellHandler extends Handler{
    @Override
    protected String handleWork(String input) {
        return input.replaceAll("labda", "lambda");
    }
}
  • Класс AddFooterHandler, конец обработчика письма
public class AddFooterHandler extends Handler{
    @Override
    protected String handleWork(String input) {
        return  input + " Kind regards";
    }
}
public class ChainMain {
    public static void main(String[] args) {
        AddHeaderHandler addHeaderHandler = new AddHeaderHandler();
        CheckSpellHandler checkSpellHandler = new CheckSpellHandler();
        AddFooterHandler addFooterHandler = new AddFooterHandler();
        addHeaderHandler.setSuccessor(checkSpellHandler);
        checkSpellHandler.setSuccessor(addFooterHandler);
        String test = addHeaderHandler.handle("labda");
        System.out.println(test);
    }
}

Наконец, консоль выводит это обработанное письмо:

From Raoul, Mario and Alan: lambda Kind regards

3. Модель цепочки ответственности, параметризация поведения, лямбда-рефакторинг

Здесь используется функциональный интерфейс Function Java 8. Метод apply вводит параметр типа T и возвращает тип R. И T, и R имеют тип String, что соответствует нашей обработке букв, и ввод и вывод имеют тип String. Поскольку наше ядро ​​лежит в логике обработки писем, мы объединяем функциональный интерфейс Java8 для параметризации поведения и реализации логики обработки писем.

  • Function<T,R>
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
  • LambdaHandler
public class LambdaHandler {

    public static Function<String, String> addHeaderHandler() {
        return (input) -> "From Raoul, Mario and Alan: " + input;
    }

    public static Function<String, String> checkSpellHandler() {
        return (input) -> input.replaceAll("labda", "lambda");
    }

    public static Function<String, String> addFooterHandler() {
        return (input) -> input + " Kind regards";
    }
}
  • ChainMain
public class ChainMain {
    public static void main(String[] args) {
        Function<String, String> addHeaderHandler = LambdaHandler.addHeaderHandler();
        Function<String, String> checkSpellHandler = LambdaHandler.checkSpellHandler();
        Function<String, String> addFooterHandler = LambdaHandler.addFooterHandler();
        String test = addHeaderHandler.andThen(checkSpellHandler).andThen(addFooterHandler).apply("labda");
        System.out.println(test);
    }
}
  • Наконец, консоль выводит это обработанное письмо:
From Raoul, Mario and Alan: lambda Kind regards

Основная функция — это метод andThen по умолчанию интерфейса Function.В дополнение к встроенному функциональному интерфейсу Function, который имеет метод andThen по умолчанию, встроенные функциональные интерфейсы, такие как Consumer также предоставьте метод andThen по умолчанию, большинство из которых можно использовать для удовлетворения наших потребностей. Мы видим, что параметр метода метода andThen также является функциональным интерфейсом, таким же, как он сам.Function<T,R>, но дженерики здесь имеют подстановочные знаки нижней границы и подстановочные знаки верхней границыFunction<? super R, ? extends V> after, конечно, нам не нужно изучать это некоторое время, потому что интерфейсы, которые мы реализуем, являются входными параметрами, а возвращаемые результаты имеют тип String.Objects.requireNonNull(after);Во-первых, оцените, что входящий параметр не может быть пустым, ведь это реализация логики обработки следующего шага обработки.(T t) -> after.apply(apply(t));Этот код работает, он разделен на два шага, первый шаг — выполнить свой собственныйapply(t)метод, то есть на текущем шаге сначала обрабатывается узел, затем возвращается результат обработки, а затем узел (результат обработки этого шага) обрабатывается на следующем шаге, то естьafter.apply(apply(t))

@FunctionalInterface
public interface Function<T, R> {
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
}

Конечно, для последнего шага обработки узла нам нужно выполнить приложение в возвращаемой в конце Function и вызвать метод реализации последнего шага обработки, а именно


String test = addHeaderHandler.andThen(checkSpellHandler).andThen(addFooterHandler).apply("labda");

Если в этой статье есть какие-либо недостатки, пожалуйста, поправьте меня или сделайте хорошие предложения ◕‿◕.Спасибо.

использованная литература: "Java8 бой"