Метод шаблона, преобразованный с использованием Java8, действительно yyds

Java задняя часть

GitHub 21.3k Звездный путь Java-инженера к тому, чтобы стать богом, не приходите и не узнайте об этом!

Путь Java-инженера с 21,3 тысячами звезд GitHub к тому, чтобы стать богом, разве вы не хотите узнать об этом!

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

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

метод предыдущего шаблона

В моей предыдущей статье "Шаблоны проектирования — шаблонный подходВ статье приведен пример:

Когда мы идем в бизнес-зал банка для ведения бизнеса, нам необходимо выполнить следующие шаги: 1. Получить номер, 2. Занять дело и 3. Оценка.

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

Мы можем инкапсулировать весь бизнес в абстрактный класс:

/**
 * 模板方法设计模式的抽象类
 * @author hollis
 */
public abstract class AbstractBusinessHandler {
    /**
     * 模板方法
     */
    public final void execute(){
        getNumber();
        handle();
        judge();
    }
    /**
     * 取号
     * @return
     */
    private void getNumber(){
        System.out.println("number-00" + RandomUtils.nextInt());
    }
    /**
     * 办理业务
     */
    public abstract void handle(); //抽象的办理业务方法,由子类实现
    /**
     * 评价
     */
    private void judge(){
        System.out.println("give a praised");
    }
}

Мы определяем класс выполнения в классе, который упорядочивает три метода: getNumber, handle и Judge. этоМетод шаблона.

Среди них getNumber и Judge имеют общие реализации, только метод handle является абстрактным и должен быть переписан подклассами в соответствии с реальным бизнес-контентом.

С этим абстрактным классом и методом шаблона, когда мы хотим реализовать «бизнес по внесению денег», нам нужно только наследовать AbstractBusinessHandler и переопределить метод дескриптора:

public class SaveMoneyHandler extends AbstractBusinessHandeler {
    @Override
    public void handle() {
        System.out.println("save 1000");
    }
}

Таким образом, когда мы выполняем бизнес-логику экономии денег, нам нужно только вызвать метод выполнения SaveMoneyHandler:

public static void main(String []args){
    SaveMoneyHandler saveMoneyHandler = new SaveMoneyHandler();
    saveMoneyHandler.execute();
}

Выходной результат:

number-00958442164
save 1000
give a praised

Выше приведена реализация простого шаблонного метода. Используя методы шаблона, это может помочь нам повторно использовать код в значительной степени.

Поскольку нам приходится обрабатывать много операций в банке, нам может понадобиться определить множество классов реализации:

//取钱业务的实现类
public class DrawMoneyHandler extends AbstractBusinessHandeler {
    @Override
    public void handle() {
        System.out.println("draw 1000");
    }
}

//理财业务的实现类
public class MoneyManageHandler extends AbstractBusinessHandeler{
    @Override
    public void handle() {
        System.out.println("money manage");
    }
}

В течение долгого времени разработчики в основном использовали шаблонный метод, подобный приведенному выше примеру: вам нужно подготовить абстрактный класс, реализовать некоторую логику в виде конкретных методов и конкретных конструкторов, а затем объявить некоторые абстрактные методы, чтобы позволить подклассам реализовать оставшиеся. логика. Различные подклассы могут по-разному реализовывать эти абстрактные методы и, таким образом, иметь разные реализации оставшейся логики.

но,В Java 8 есть еще один способ реализации шаблонных методов, и нет необходимости определять слишком много классов реализации.

Функциональное программирование с Java 8

В 2014 году Oracle выпустила Java 8, и самой важной новой функцией Java 8 является поддержка функционального программирования.

Java 8 вjava.util.functionСледующее добавляет серию функциональных интерфейсов. Среди них Потребитель, Поставщик, Предикат, Функция и так далее.

В этой статье в основном мы хотим представить Поставщика и Потребителя, два пользовательских интерфейса, которые могут помочь нам очень хорошо преобразовать метод шаблона. Это всего лишь краткое введение в их использование, и мы не будем вдаваться в подробности. Если вы хотите узнать больше об использовании, вы можете сами погуглить.

Supplier

Поставщик – этотип питанияПроще говоря, интерфейс — это метод, который возвращает какое-то значение.

Самый простой Поставщик — это следующий код:

public List<String> getList() {
    return new ArrayList();
}

Использование Поставщика выражается как:

Supplier<List<String>> listSupplier = ArrayList::new;

Consumer

Потребительский интерфейспотреблениеИнтерфейсы, просто, это метод определенного значения (например, параметры метода), который подвергается эксплуатации.

Самый простой Consumer — это следующий код:

public void sum(String a1) {
    System.out.println(a1);
}

Использование представления Consumer:

Consumer<String> printConsumer = a1 -> System.out.println(a1);

Использование Consumer, наиболее распространенным примером являетсяStream.forEach(Consumer)такое использование,

Он принимает Consumer, который потребляет элементы в итерируемом потоке, и выполняет некоторые действия с каждым элементом, например печать:

Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);

Шаблонные методы начиная с Java 8

После представления Consumer и Supplier в Java 8 давайте посмотрим, как преобразовать метод шаблона, который мы представили ранее.

Сначала мы определяем класс BankBusinessHandler и переопределяем метод execute. Этот метод имеет входной параметр типа Consumer, а затем удаляет метод дескриптора. Метод перестроенного шаблона выглядит следующим образом:

/**
 * @author Hollis
 */
public class BankBusinessHandler {
    private void execute(Consumer<BigDecimal> consumer) {
        getNumber();

        consumer.accept(null);

        judge();
    }

    private void getNumber() {
        System.out.println("number-00" + RandomUtils.nextInt());
    }

    private void judge() {
        System.out.println("give a praised");
    }
}

В реализованном нами шаблонном методе execute расположены getNumber, Judge и Consumer.accept, где Consumer.accept — это конкретная бизнес-логика, которая может заключаться в накоплении денег, снятии денег, финансировании и т.д. Его нужно передавать, когда другие методы вызывают execute.

В настоящее время, когда мы хотим реализовать бизнес по «сбережению денег», нам нужно добавить в класс BankBusinessHandler следующие методы:

/**
 * @author Hollis
 */
public class BankBusinessHandler {

    public void save(BigDecimal amount) {
        execute(a -> System.out.println("save " + amount));
    }
}

В методе save вызовите метод execute и передайте во входном параметре объект Comsumer, реализующий бизнес-логику «экономии денег».

Таким образом, когда мы выполняем бизнес-логику внесения денег, нам нужно только вызвать метод сохранения BankBusinessHandler:

public static void main(String[] args) throws {
    BankBusinessHandler businessHandler = new BankBusinessHandler();
    businessHandler.save(new BigDecimal("1000"));
}

Выходной результат:

number-001736151440
save1000
give a praised

Как и выше, когда мы хотим реализовать бизнес-логику, такую ​​как снятие денег и управление финансами, это похоже на экономию денег:

/**
 * @author Hollis
 */
public class BankBusinessHandler {

    public void save(BigDecimal amount) {
        execute(a -> System.out.println("save " + amount));
    }

    public void draw(BigDecimal amount) {
        execute(a -> System.out.println("draw " + amount));
    }

    public void moneyManage(BigDecimal amount) {
        execute(a -> System.out.println("draw " + amount));
    }
}

Как видите, используя Comsumer в Java 8, мы преобразовали метод шаблона,После преобразования больше не требуются абстрактные классы и абстрактные методы, и нет необходимости создавать класс реализации для каждого бизнеса.. Мы можем объединить всю бизнес-логику в одном бизнес-классе. Это очень удобно для последующей работы и обслуживания этого кода.

Я рассказал, как использовать Consumer для преобразования метода шаблона, так в чем же польза от Supplier?

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

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

Независимо от того, как был получен номер, конечным результатом является получение номера, и тип полученного номера может быть другим, и конкретные услуги могут быть разными.Например, номер VIP будет отправлен на стойку VIP для бизнеса, и Т. Д.

Для реализации такой бизнес-логики нужно использовать Supplier,Поставщик — это «поставщик», которого можно использовать для настройки «логики подсчета».

Во-первых, нам нужно преобразовать метод шаблона:

/**
 * 模板方法
 */
protected void execute(Supplier<String> supplier, Consumer<BigDecimal> consumer) {

    String number = supplier.get();
    System.out.println(number);


    if (number.startsWith("vip")) {
        //Vip号分配到VIP柜台
        System.out.println("Assign To Vip Counter");
    }
    else if (number.startsWith("reservation")) {
        //预约号分配到专属客户经理
        System.out.println("Assign To Exclusive Customer Manager");
    }else{
        //默认分配到普通柜台
        System.out.println("Assign To Usual Manager");
    }

    consumer.accept(null);

    judge();
}

После преобразования во входной параметр execute добавляется поставщик, и этот поставщик может указать номер. Что касается того, как получить номер, передайте его методу, который вызывает execute.

После этого мы можем определить несколько методов депозита, а именно VIP-депозит, резервационный депозит и обычный депозит:

public class BankBusinessHandler extends AbstractBusinessHandler {

    public void saveVip(BigDecimal amount) {
        execute(() -> "vipNumber-00" + RandomUtils.nextInt(), a -> System.out.println("save " + amount));
    }

    public void save(BigDecimal amount) {
        execute(() -> "number-00" + RandomUtils.nextInt(), a -> System.out.println("save " + amount));
    }

    public void saveReservation(BigDecimal amount) {
        execute(() -> "reservationNumber-00" + RandomUtils.nextInt(), a -> System.out.println("save " + amount));
    }

}

В нескольких различных методах депозита реализуйте различную логику получения номеров, инкапсулируйте логику получения номеров в поставщике, а затем передайте ее в метод execute.

Код теста выглядит следующим образом:

BankBusinessHandler businessHandler = new BankBusinessHandler();
businessHandler.saveVip(new BigDecimal("1000"));

Выходной результат:

vipNumber-001638110566
Assign To Vip Counter
save 1000
give a praised

Выше мы преобразовали шаблон метода шаблона с помощью Comsumer и Supplier.

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

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

Суммировать

Выше мы представили, что такое шаблон метода шаблона и как использовать Comsumer и Supplier для преобразования шаблона метода шаблона.

Такой подход часто используется в нашей повседневной разработке.На самом деле, я не думаю, что примеры в этой статье могут полностью выразить то, что я хочу выразить, но логика в нашем реальном бизнесе сложнее.

Поэтому это требует от каждого понимания и много практики. Если вы использовали шаблон метода шаблона в своем коде, его необходимо преобразовать с помощью методов, описанных в этой статье.

Если вы не использовали шаблон метода шаблона, это означает, что в вашем приложении должно быть много повторяющегося кода, поэтому поторопитесь и используйте его.

Как инженер-разработчик, мы должны сделать все возможное, чтобы исключить дублирование кода в приложении.

Об авторе:Hollis, человек с уникальным увлечением программированием, технический эксперт Alibaba, соавтор «Трех курсов для программистов» и автор серии статей «Дорога к Java-инженерам».

Обратите внимание на общедоступный номер【Hollis], фоновый ответ «Карта Бога» может получить расширенную карту разума инженеров Java.