Хоть программист

Шаблоны проектирования: структурные шаблоны классов и объектов проектирования

Адаптер, декоратор, прокси, информационный эксперт, композит, мост, слабая связь, легковес, защищенные вариации и фасад

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

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

Есть следующие 10 типов структурных шаблонов проектирования.

  • Шаблон адаптера
  • Образец моста
  • Составной узор
  • Шаблон декоратора
  • Низкое сцепление
  • Выкройка наилегчайшего веса
  • Узор фасада
  • Шаблон прокси
  • Информационный эксперт
  • Защищенные вариации

ABCD (адаптер, мост, композит, декоратор)

Шаблон адаптера

Намерение

Шаблон адаптера - это структурный шаблон проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе.

Решение

Он реализует интерфейс, известный его клиентам, и предоставляет доступ к экземпляру класса, неизвестному его клиентам.

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

Пример из реальной жизни

Исходная мощность составляет 220 вольт, и для работы ее необходимо настроить на 100 вольт.

Следующий код решает эту проблему. Он определяет HighVoltagePlug (адаптер), Plug интерфейс (цель), AdapterPlug (адаптер).

Цель: Plug.java

public interface Plug {
    public int recharge();
}

Адаптированный: HighVoltagePlug.java

public class HighVoltagePlug{
    public int recharge() {
        //Power is 220 Voltage
        return 220; 
    }
}

Адаптер: AdapterPlug.java

public class AdapterPlug implements Plug {
    @Override
    public int recharge() {
        HighVoltagePlug bigplug = new HighVoltagePlug();
        int v = bigplug.recharge();
        v = v - 120;
        return v;
    }
}

AdapterClient: AdapterClient.java.

public class AdapterClient {
    public static void main(String[] args) {
        HighVoltagePlug oldPlug = new HighVoltagePlug();
        System.out.println(plug.recharge() + " too much voltage");
        
        Plug newPlug = new AdapterPlug();
        System.out.println("Adapter into " + plug.recharge() + " voltage");
    }
}

Примеры использования

Если вы хотите использовать существующий класс, а его интерфейс не соответствует нужному вам.

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

Где должен происходить перевод интерфейса между несколькими источниками.

Образец моста

Намерение

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

Решение

На следующей диаграмме показана возможная реализация моста.

  • Абстракция: это компонент абстракции.
  • Разработчик: это абстрактная реализация.
  • RefinedAbstraction: это усовершенствованный компонент.
  • ConcreateImplementors: это конкретные реализации.

Пример из реальной жизни

Разные люди могут носить разную одежду, например, мужчина, женщина, мальчик и девочка.

AbstractionImpl: Person.java

public abstract class Person {

    protected String name;
    protected Clothing cloth;

    public Person(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Clothing getCloth() {
        return cloth;
    }

    public void setCloth(Clothing cloth) {
        this.cloth = cloth;
    }
}

Разработчик: Clothing.java.

public abstract class Clothing {

    protected String name;
    
    public Clothing(String name) {
        super();
        this.name = name;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

ConcreateImplementor: Jacket.java

public class Jacket extends Clothing {

    public Jacket(String name) {
        super(name);
    }
}

RefinedAbstraction: Woman.java.

public class Woman extends Person {
    
    public Woman(String name) {
        super(name);
    }

    @Override
    public void dress() {
        System.out.println(name + " wear " + cloth.getName());
    }
}

Клиент: BridgeClient.java

public class BridgeClient {
    public static void main(String[] args) {

        Person woman = new Woman("Woman");

        Clothing jacket = new Jacket("Jacket");

        // a woman wear jacket
        woman.setCloth(jacket); 
        woman.dress();
    }
}

Примеры использования

Избегайте постоянной привязки абстракции к ее реализации.

И абстракции, и их реализации должны быть расширяемыми с помощью подклассов.

Изменения в реализации абстракции не должны влиять на клиентов; то есть вам не придется перекомпилировать их код.

Составной узор

Намерение

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

Решение

Шаблон Composite объединяет объекты в древовидные структуры для представления либо всей иерархии, либо ее части.

  • Компонент - это абстракция для листьев и композитов. Он определяет интерфейс, который должен быть реализован объектами в композиции.
  • Листья - это объекты, у которых нет дочерних элементов. Они реализуют сервисы, описываемые интерфейсом Component.
  • Composite хранит дочерние компоненты в дополнение к методам реализации, определенным интерфейсом компонента. Композиты реализуют методы, определенные в интерфейсе Component, путем делегирования дочерним компонентам. Кроме того, композиты предоставляют дополнительные методы для добавления, удаления, а также получения компонентов.
  • Клиент управляет объектами в иерархии с помощью интерфейса компонента.

Пример из реальной жизни

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

Компонент: IEmployee.java

interface IEmployee {
    
    void printStructures();
    int getEmployeeCount();

}

Составной: CompositeEmployee.java

class CompositeEmployee implements IEmployee {

    private int employeeCount=0;
    private String name;
    private String dept;

    //The container for child objects
    private List<IEmployee> controls;

    public CompositeEmployee(String name, String dept){

        this.name = name;
        this.dept = dept;
        controls = new ArrayList<IEmployee>();

    }

    public void addEmployee(IEmployee e){

        controls.add(e);

    }

    public void removeEmployee(IEmployee e){

        controls.remove(e);

    }

    @Override
    public void printStructures(){

        System.out.println("\t" + this.name + " works in  " + this.dept);

        for(IEmployee e: controls){
            e.printStructures();
        }

    }

    @Override
    public int getEmployeeCount(){
        employeeCount=controls.size();
        for(IEmployee e: controls){
            employeeCount+=e.getEmployeeCount();
        }
        return employeeCount;
    }

}

Leaf: Employee.java

class Employee implements IEmployee{

    private String name;
    private String dept;
    private int employeeCount=0;

    public Employee(String name, String dept){

        this.name = name;
        his.dept = dept;

    }

    @Override
    public void printStructures(){
        System.out.println("\t\t"+this.name + " works in  " + this.dept);
    }

    @Override
    public int getEmployeeCount(){
        return employeeCount;

    }

}

Примеры использования

Вы хотите представить всю иерархию или часть иерархии объектов; где клиенты могут игнорировать разницу между составами объектов и отдельными объектами.

Вы можете применить этот шаблон к структуре, которая может иметь любой уровень сложности.

Шаблон декоратора

Намерение

Шаблон декоратора позволяет добавлять или удалять функциональные возможности объекта без изменения внешнего вида или функции объекта.

Решение

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

  • Компонент - это интерфейс для объектов, к которым можно динамически добавлять обязанности.
  • ConcreteComponent определяет объект, к которому можно добавить дополнительные обязанности.
  • Декоратор поддерживает ссылку на объект Component и определяет интерфейс, соответствующий интерфейсу Component.
  • ConcreteDecorators расширяют функциональные возможности компонента, добавляя состояние или поведение.

Пример из реальной жизни

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

Примеры использования

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

Когда вы хотите добавить к объекту обязанности, которые вы, возможно, захотите изменить в будущем.

Если расширение с помощью статического подкласса нецелесообразно.

F2P (Легковес, Фасад, Прокси)

Выкройка наилегчайшего веса

Намерение

- Шаблон «Легковес» уменьшает количество низкоуровневых детализированных объектов в системе за счет совместного использования объектов.

Решение

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

  • Клиент: код клиента.
  • FlyweightFactory: создает легковесы, если они не существуют, и возвращает их из пула, если они существуют.
  • Легковес: абстрактный наилегчайший вес.
  • ConcreateFlyweight: легковес, предназначенный для совместного использования со своими сверстниками.

Пример из реальной жизни

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

Примеры использования

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

  • Приложение использует большое количество объектов.
  • Затраты на хранение высоки из-за количества предметов.
  • Приложение не зависит от идентичности объекта.

Узор фасада

Намерение

Шаблон «Фасад» предоставляет единый интерфейс для группы интерфейсов в подсистеме.

Решение

Он определяет интерфейс более высокого уровня, который упрощает использование подсистемы, поскольку у вас есть только один интерфейс.

Пример из реальной жизни

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

Примеры использования

Если вы хотите предоставить простой интерфейс для сложной подсистемы.

В случае, если существует много зависимостей между клиентами и классами реализации абстракции

Когда вы хотите наслоить свои подсистемы.

Шаблон прокси

Существует несколько типов реализаций шаблона прокси, из которых наиболее распространены удаленный прокси и виртуальный прокси.

Намерение

Шаблон Proxy предоставляет суррогатный объект или объект-заполнитель для управления доступом к исходному объекту.

Решение

Пример из реальной жизни

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

Примеры использования

Вам нужна более универсальная или сложная ссылка на объект, чем простой указатель.

Шаблоны GRASP

GRASP называет и описывает основные принципы распределения обязанностей.

Информационный эксперт

Мы смотрим на паттерн эксперта (или паттерн информационного эксперта). Это довольно просто, но очень важно.

Намерение

Каков основной принцип распределения обязанностей между объектами?

Решение

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

Пример из реальной жизни

Рассмотрим игру «Монополия». Предположим, объект хочет ссылаться на Square, учитывая его имя. Кто несет ответственность за знание площади, учитывая ее название?

Наиболее вероятным кандидатом является Правление, потому что оно состоит из квадратов.

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

Примеры использования

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

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

Защищенные вариации

Намерение

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

Решение

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

Принцип «Не разговаривать с незнакомцами», который гласит, что методы объекта должны отправлять сообщения (т. Е. Использовать методы) только тех объектов, с которыми он непосредственно знаком.



Пример из реальной жизни

Инкапсуляция данных, интерфейсы, полиморфизм, косвенность и стандарты мотивированы Protected Variations.

Примеры использования

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

Заключение

Структурные шаблоны влияют на приложения по-разному, например, шаблон «Адаптер» позволяет двум несовместимым системам взаимодействовать, а шаблон «Фасад» позволяет представить пользователю упрощенный интерфейс, не удаляя все параметры, доступные в системе.

Легко, правда?