[Серия «Учимся вместе»] Итератор и комбинация: хотя это немного бесполезно

Шаблоны проектирования
[Серия «Учимся вместе»] Итератор и комбинация: хотя это немного бесполезно

шаблон итератора

намерение

Предоставляет способ последовательного доступа к элементам в агрегатном объекте без раскрытия внутреннего представления объекта.

Рождение шаблона итератора

【Product】: Эй, есть хорошие новости, наш ресторан поглотил кофейню Moon Buck! чудесный! Бонус по итогам года фиксирован!

【Разработка】: Да! Да! Да!

【Product】: Но они, кажется, ответили на вопрос. Похоже, система заказов Moon Barker не совместима с нашей системой. Что происходит? Это не просто меню?

【Развитие】: О! Нет! Это должно быть вызвано их разными структурами данных, и есть проблема с обходом!

[Продукт]: Что мне делать? Босс, ты подумай об этом!

[В разработке]: Босс, мы можем извлечь метод обхода? Мы можем пройти операцию, не рассматривая различные детали, просто нужно управлять классом обхода.

[БОСС]: Что за класс обхода, он называется итератор, ладно! На самом деле, JDK очень хорошо поддерживает итераторы, но наш бизнес также имеет небольшую специализацию. Давайте сделаем, как вы сказали. Если мы не сделаем это хорошо, только что упомянутая премия в конце года исчезнет.

[Разработчик]: О, ладно (улыбка на лице, ММП в сердце)

Основной код HeadFirst

иметь итератор

"Определение держателей итераторов Необязательный код"

/**
 * ******************************
 * description:  迭代器持有者
 * ******************************
 */
public interface MyContainer {

    MyIterator getIterator();
}

"интерфейс итератора"

/**
 * ******************************
 * description:  迭代器接口
 * ******************************
 */
public interface MyIterator {

    boolean hasNext();

    Object next();
}

"меню еды класса работы итератора"

public class FoodRepository implements MyContainer {

    String[] names = {"宫保鸡丁", "麻辣香锅", "油闷大虾"};

    @Override
    public MyIterator getIterator() {
        return new NameIterator();
    }

    private class NameIterator implements MyIterator {

        private int index;

        @Override
        public boolean hasNext() {
            return index < names.length;
        }

        @Override
        public Object next() {
           return hasNext() ? names[index++] : null;
        }

        NameIterator() {
            index = 0;
        }
    }
}

"Кофейное меню класса работы итератора"

public class CoffeeRepository implements MyContainer {

    List<String> names = Arrays.asList("雀巢咖啡", "黑糖玛奇朵", "半点寂寞");

    @Override
    public MyIterator getIterator() {
        return new NameIterator();
    }

    private class NameIterator implements MyIterator {

        private int index;

        @Override
        public boolean hasNext() {
            return index < names.size();
        }

        @Override
        public Object next() {
           return hasNext() ? names.get(index++) : null;
        }

        NameIterator() {
            index = 0;
        }
    }
}

"Тестовый класс Наблюдайте за проявлением вызова"

public class App {

    public static void main(String[] args){
        // 餐厅菜单
        FoodRepository food = new FoodRepository();
        MyIterator foodIterator = food.getIterator();
        while (foodIterator.hasNext()) {
            System.out.println("Food: -> " + foodIterator.next());
        }

        CodeUtils.spilt();

        // 咖啡菜单
        CoffeeRepository coffee = new CoffeeRepository();
        MyIterator coffeeIterator = coffee.getIterator();
        while (coffeeIterator.hasNext()) {
            System.out.println("Coffee: -> " + coffeeIterator.next());
        }
    }
}

Итерация в JDK

public class App {
    
    public static void main(String[] args){
        // JDK
        List<String> names = Arrays.asList("Han", "John", "Tomams");
        Iterator<String> iterable = names.iterator();
        while (iterable.hasNext()) {
            System.out.println("JDK Iterator: -> " + iterable.next());
        }

        CodeUtils.spilt();

        // JDK
        names.forEach(s -> System.out.println("JDK forEach: -> " + s));
    }
}

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

Идея оформления паттерна итератора:

  • Итератор итератор
  • Concretelterator Конкретный итератор
  • Совокупный сбор
  • Сбор бетона ConcreteAggregate

Проще говоря,

  1. Нам нужно указать тип коллекции (массив, связанный список, карта, древовидная структура или обычный список)
  2. Нам нужно определить поведение итератора, есть ли следующий (обход завершен), значение, удаление и т.д.
  3. Поведение или алгоритм обхода реализованы в конкретном итераторе, а кодирование выполняется в соответствии с различными структурами данных и бизнес-требованиями для достижения согласованного доступа, но с разными деталями.

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

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

  • Принцип единой ответственности

Примечание: класс итератора включает в дизайн только функцию итерации коллекции.Он извлекает обход в исходной структуре данных для достижения эффекта высокой связности.

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

Какая сцена подходит для использования

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

Код / практическое применение в жизни

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

UML-диаграмма шаблона итератора

Комбинированный режим

намерение

Компоновка объектов в древовидные структуры для представления иерархий «часть-целое». Composite позволяет пользователям последовательно использовать отдельные объекты и составные объекты.

Говорящий человек: подумайте о классе File в Java

Ошибки в комбинированном режиме

Комбинирование узоров — это не сочетание кучи узоров!

Рождение комбинированной модели

[Разработчик]: Босс, мне так больно, когда я пишу класс меню!

[БОСС]: Что случилось?

[В разработке]: В меню есть настоящие блюда, как и в родительском меню.Они должны поддерживать два набора логики.Неудобно смешивать их вместе!

[БОСС]: Почему вы не чувствуете себя неловко, когда работаете с файлами? Почему бы вам не использовать свой мозг, чтобы думать об абстракции!

【Развитие】: Да! Я изменю код!

Основной код HeadFirst

"определить абстрактное поведение"

/**
 * ******************************
 * description:  定义抽象行为
 * ******************************
 */
public abstract class MenuComponent {

    public String name;

    /***
     * 添加
     */
    public abstract void add(MenuComponent component) throws Exception;

    /***
     * 移除
     */
    public abstract void remove(MenuComponent component) throws Exception;

    /***
     * 获取菜单名
     */
    public abstract String getName();

    /***
     * 获取子菜单
     */
    public abstract MenuComponent getChild(int i) throws Exception;

    /***
     * 打印菜单
     */
    public abstract void print();
}

"достичь «всего»"

public class Menu extends MenuComponent{

    List<MenuComponent> menuComponents = new ArrayList<>();

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

    @Override
    public void add(MenuComponent component) {
        this.menuComponents.add(component);
    }

    @Override
    public void remove(MenuComponent component) {
        this.menuComponents.remove(component);
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public MenuComponent getChild(int i) {
        return menuComponents.get(i);
    }

    @Override
    public void print() {
        System.out.println("当前菜单项: " + getName());
        for (MenuComponent component : menuComponents) {
            component.print();
        }
    }
}

"Реализовать «части»"

public class MentItem extends MenuComponent{

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

    @Override
    public void add(MenuComponent component) throws Exception {
        throw new Exception("无法添加");
    }

    @Override
    public void remove(MenuComponent component) throws Exception {
        throw new Exception("无法移除");
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public MenuComponent getChild(int i) throws Exception {
        throw new Exception("无子节点");
    }

    @Override
    public void print() {
        System.out.println("    食物名: " + getName());
    }
}

"тестовый класс"

public class App {

    /***
     * 推荐代码阅读顺序:
     *
     * @see MenuComponent
     * @see Menu
     * @see MentItem
     */
    public static void main(String[] args) {
        Menu meat = new Menu("炒菜类");

        MentItem item1 = new MentItem("宫保鸡丁");
        MentItem item2 = new MentItem("剁椒鸡蛋");
        MentItem item3 = new MentItem("鱼香肉丝");

        Menu vegetable = new Menu("素食");
        MentItem v1 = new MentItem("酸辣土豆丝");
        MentItem v2 = new MentItem("爆炒包菜");

        meat.add(item1);
        meat.add(item2);
        meat.add(item3);

        vegetable.add(v1);
        vegetable.add(v2);

        meat.add(vegetable);

        meat.print();
    }
}


/***
 * 输出内容:
 *
 * 当前菜单项: 炒菜类
 *     食物名: 宫保鸡丁
 *     食物名: 剁椒鸡蛋
 *     食物名: 鱼香肉丝
 * 当前菜单项: 素食
 *     食物名: 酸辣土豆丝
 *     食物名: 爆炒包菜
 */

Идеи дизайна для комбинированного режима:

  • Компонент объявляет интерфейс или абстрактный класс для составного объекта.
  • Листовой узел (минимальная единица)
  • Составной составной узел (то есть узел, который также имеет дочерние узлы)
  • Клиент клиент, абонент

Проще говоря,

  1. Общее поведение абстрактных листовых узлов и составных узлов (узлов с дочерними элементами), когда нам нужна древовидная структура
  2. Пусть оба реализуют один и тот же интерфейс

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

Какая сцена подходит для использования

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

Код / практическое применение в жизни

Это все еще неуместный пример.Когда мы работаем с файлами и папками, у нас есть такие функции, как перемещение, копирование, переименование, просмотр размера файла и т. д. Для Java его базовой реализацией является是否是文件夹метод различения, но на самом деле это и основная идея режима композиции, то есть для объекта, представляющего часть, и объекта целого, он имеет единое поведение операции

UML-диаграмма комбинированного шаблона

Суммировать

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

Связанные ссылки на код

Адрес GitHub

  • С учетом кейсов в двух классических книгах "HeadFirst" и "GOF"
  • Предоставляет дружественное руководство по чтению

В этой статье используетсяmdniceнабор текста