Чем отличаются Шаблоны Прокси, декоратора, адаптера и моста?

Я смотрел на шаблон прокси, и мне кажется, что он очень похож на декоратор, адаптер и шаблоны мостов. Я что-то не так понял? Какая разница? Почему я должен использовать шаблон прокси по сравнению с другими? Как вы использовали их в прошлом в реальных проектах?

13 ответов


Прокси, декоратор, адаптер и мост-все это варианты "обертывания" класса. Но их использование отличается.

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

  • оформителя также называется " Smart Proxy."Это используется, когда вы хотите, чтобы добавить функциональность к объекту, но не путем расширения это тип объекта. Это позволяет делать это во время выполнения.

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

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

  • фасад-это интерфейс более высокого уровня (читай: более простой) для подсистемы одного или нескольких классов. Предположим, у вас есть сложная концепция, которая требует представления нескольких объектов. Внесение изменений в этот набор объектов запутывает, потому что вы не всегда знаете, какой объект имеет метод, который вам нужно вызвать. Пришло время писать. фасад, предоставляющий высокоуровневые методы для всех сложных операций, которые можно выполнить с коллекцией объектов. Пример: модель домена для школьного раздела с такими методами, как countStudents(), reportAttendance(), assignSubstituteTeacher() и так далее.


Как говорит Ответ Билла, их варианты использования разные.

, Так и их структуры.

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

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

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


мой взгляд на эту тему.

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

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

адаптер

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

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

адаптеры защищают одну команду от изменчивого кода от других команд; инструмент Спасителя жизни при работе с оффшорными командами; -)

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

адаптер помогает обойти Ограничение Java только одного наследования. Он может объединить несколько adaptees под один конверт, давая впечатления от множественного наследования.

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

в JDK или базовых библиотеках не так много хороших примеров адаптеров. Разработчики приложений создают адаптеры для адаптации библиотек к приложениям конкретный интерфейс.

декоратор

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

декораторы обычно добавляют (прозрачно) функциональность к обернутому объекту, такому как ведение журнала, шифрование, форматирование или сжатие. Эта новая функциональность может принести много нового кодекса. Следовательно, декораторы обычно намного "толще", чем адаптеры.

декоратор должен быть подклассом интерфейса субъекта. Их можно использовать прозрачно вместо своих тем. См. BufferedOutputStream, он по-прежнему OutputStream и может использоваться как таковой. Это основное техническое отличие от адаптеров.

примеры текстовой книги всего семейства декораторов легко в JDK - JAVA IO. Все классы как BufferedOutputStream, FilterOutputStream и ObjectOutputStream несколько декораторов OutputStream. Они могут быть наслоены луком, где один декоратор украшен снова, добавляя больше функциональности.

Прокси

Proxy не является типичной оболочкой. Обернутый объект, субъект прокси, может еще не существовать во время создания прокси. Прокси часто создает его внутренне. Это может быть тяжелый объект, созданный по требованию, или удаленный объект в другом JVM или другом сетевом узле и даже не Java-объект, компонент в собственном коде. Он вообще не должен обертывать или делегировать другому объекту.

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

  • удаленный Прокси-субъект находится на удаленном сервере, другой JVM или даже не Система Java. Прокси переводит вызовы методов в вызовы RMI/REST/SOAP или все, что нужно, защищая клиента от воздействия к основному технология.

  • Lazy Load Proxy-полностью инициализировать объект только при первом использовании или первое интенсивное использование.

  • Access Proxy-контроль доступа к субъекту.

фасад

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

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

мост

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

различия в конструкторах

шаблон различия также очевидны при взгляде на их конструкторы.

  • Прокси не обертывает существующий объект. Нет никакой темы в конструктор.

  • декоратор и адаптер обертывает уже существующий объект, и это обычно
    предоставляется в конструкторе.

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

реальной жизни пример – JAXB маршаллинг адаптер. Назначение этого адаптера-отображение простой квартиры класс для более сложной структуры требуется внешне и для предотвращения "загрязнения" предметного класса чрезмерными аннотациями.


во многих шаблонах GoF есть много перекрытий. Все они построены на силе полиморфизма и иногда отличаются только по намерениям. (стратегия против государства)

мое понимание шаблонов увеличилось в 100 раз после прочтения Головы Первый Дизайн Шаблоны.

Я настоятельно рекомендую его!


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

Я украшения ключевые моменты.

оформитель:

  1. добавить поведение объекта во время выполнения. Наследование является ключом к достижению этой функциональности, которая является как преимуществом, так и недостатком этого шаблона.
  2. он изменяет поведение of взаимодействие.

например (с цепочкой ) : java.io классы пакетов, связанные с InputStream & OutputStream интерфейсы

FileOutputStream fos1 = new FileOutputStream("data1.txt");  
ObjectOutputStream out1 = new ObjectOutputStream(fos1);

Прокси:

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

например: java.rmi классы пакета.

адаптер:

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

например java.io.InputStreamReader (InputStream возвращает Reader)

мост:

  1. он позволяет как абстракции, так и реализации варьироваться независимо.
  2. он использует композиция над наследованием.

например, классы коллекции в java.util. List осуществлен ArrayList.

ключ Примечания:

  1. адаптер предоставляет другой интерфейс для своей темы. Прокси обеспечивает тот же интерфейс. оформителя обеспечивает улучшенный интерфейс.
  2. адаптер изменяет интерфейс объекта,оформителя увеличивает объект обязанность.
  3. оформителя и Прокси имеют различные цели, но аналогичные структуры
  4. адаптер заставляет вещи работать после того, как они сконструированы; мост заставляет их работать, прежде чем они являются.
  5. мост разработан спереди, чтобы абстракция и реализация варьировались независимо. адаптер модифицирован, чтобы сделать несвязанные классы работать вместе
  6. оформителя предназначен для добавления обязанностей к объектам без подклассов.

посмотрите на большие вопросы SE / статьи, касающиеся примеров различных шаблонов дизайна

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

когда вы используете Узор Моста? Чем он отличается от шаблона адаптера?

различия между прокси-сервером и шаблоном декоратора


Они очень похожи, и границы между ними довольно серо. Я предлагаю вам прочитать Прокси-Шаблон и Шаблон "Декоратор" записи в вики c2.

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

чтобы суммировать записи c2, я бы сказал, что декоратор добавляет / изменяет поведение, но прокси-сервер больше связан с контролем доступа (ленивый экземпляр, удаленный доступ, безопасность и т. д.). Но, как я уже сказал, линии между ними серые, и я вижу ссылки на прокси, которые можно легко рассматривать как декораторов и наоборот.


Это цитата из Головы Первый Дизайн Шаблоны

определения принадлежат книге. Примеры принадлежат мне.

декоратор - не изменяет интерфейс, но добавляет ответственности. Предположим, у вас есть интерфейс автомобиля, когда вы реализуете это для разных моделей автомобилей (s, sv, sl), вам может понадобиться добавить больше ответственности для некоторых моделей. Как имеет люк, воздушную подушку etc..

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

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

Head First: "фасад не только упрощает интерфейс, он отделяет клиента от подсистемы компонентов. Фасады и переходники могут обернуть множественные классы, но намерение фасада упростить, пока адаптер должен преобразовать интерфейс во что-то другое."


все четыре шаблона включают обертывание внутреннего объекта / класса с внешним, поэтому они очень похожи структурно. Я бы обозначил разницу целью:--1-->

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

и изменением интерфейса между внутренними и внешними объектами:

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

Я использую его довольно часто при использовании веб-служб. Прокси-шаблон, вероятно, следует переименовать во что-то более прагматичное, например"шаблон обертки". У меня также есть библиотека, которая является прокси для MS Excel. Это упрощает автоматизацию Excel, не беспокоясь о фоновых деталях, таких как установленная версия (если таковая имеется).


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

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

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


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

цитирует детали из ответа [https://stackoverflow.com/a/350471/1984346] (Билл Karwing)

Прокси, декоратор, адаптер и мост-все это варианты "обертывания" класса. Но их использование отличается.

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

proxyclass и ObjectClass, который проксируется, должны реализовать тот же интерфейс, поэтому они взаимозаменяемы

пример-прокси дорогой объект

class ProxyHumanGenome implements GenomeInterface  {
    private $humanGenome = NULL; 

    // humanGenome class is not instantiated at construct time
    function __construct() {
    }

    function getGenomeCount() {
        if (NULL == $this->humanGenome) {
            $this->instantiateGenomeClass(); 
        }
        return $this->humanGenome->getGenomeCount();
    }
} 
class HumanGenome implement GenomeInterface { ... }
  • оформителя также называется " Smart Proxy."Это используется, когда вы хотите добавлять функциональность для объекта, но не путем расширения этого объекта тип. Это позволяет делать это во время выполнения.

DecoratorClass должен (может) реализовать расширенный интерфейс ObjectClass. Таким образом, ObjectClass может быть заменен DecoratorClass, но не наоборот.

пример-добавление функциональности добавления

class DecoratorHumanGenome implements CheckGenomeInterface  {

    // ... same code as previous example

    // added functionality
    public function isComplete() {
        $this->humanGenome->getCount >= 21000
    }
}

interface CheckGenomeInterface extends GenomeInterface {

    public function isComplete();

}

class HumanGenome implement GenomeInterface { ... }
  • адаптер используется, когда у вас есть абстрактный интерфейс, и вы хотите сопоставьте этот интерфейс с другим объектом, имеющим аналогичный функционал роль, но другой интерфейс.

имплантирование различия Прокси, декоратор, адаптер

адаптер предоставляет другой интерфейс для своей темы. Прокси предоставляет тот же интерфейс. Декоратор обеспечивает улучшенный интерфейс.

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

  • фасад-это интерфейс более высокого уровня (читай: более простой) для подсистемы один или несколько классов. Предположим, у вас есть сложная концепция, которая требует несколько объектов для представления. Внесение изменений к этому набору объектов это сбивает с толку, потому что вы не всегда знаете, какой объект имеет метод нужно вызвать. Это время, чтобы написать фасад предоставляет методы высокого уровня для всех сложных операций, которые можно выполнить к коллекции объектов. Пример: модель домена для школы раздел, с такими методами, как countStudents(), reportAttendance(), assignSubstituteTeacher() и так далее.

большая часть информации в этом ответе от https://sourcemaking.com/design_patterns, который я рекомендую как отличный ресурс для шаблонов проектирования.


Я считаю, что код даст четкие идеи (в дополнение к другим ответам). См. ниже (сфокусируйте типы, которые реализует и обертывает класс)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Proxy */

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("PROXY");
            Console.WriteLine(Environment.NewLine);

            //instead of creating here create using a factory method, the facory method will return the proxy
            IReal realProxy = new RealProxy();
            Console.WriteLine("calling do work with the proxy object ");
            realProxy.DoWork();

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("ADAPTER");
            Console.WriteLine(Environment.NewLine);

            /*Adapter*/
            IInHand objectIHave = new InHand();
            Api myApi = new Api();
            //myApi.SomeApi(objectIHave); /*I cant do this, use a adapter then */
            IActual myAdaptedObject = new ActualAdapterForInHand(objectIHave);
            Console.WriteLine("calling api with  my adapted obj");
            myApi.SomeApi(myAdaptedObject);


            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("DECORATOR");
            Console.WriteLine(Environment.NewLine);

            /*Decorator*/
            IReady maleReady = new Male();
            Console.WriteLine("now male is going to get ready himself");
            maleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReady = new Female();
            Console.WriteLine("now female is going to get ready her self");
            femaleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady maleReadyByBeautician = new Beautician(maleReady);
            Console.WriteLine("now male is going to get ready by beautician");
            maleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReadyByBeautician = new Beautician(femaleReady);
            Console.WriteLine("now female is going to get ready by beautician");
            femaleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            Console.ReadLine();


        }
    }

    /*Proxy*/

    public interface IReal
    {
        void DoWork();
    }

    public class Real : IReal
    {
        public void DoWork()
        {
            Console.WriteLine("real is doing work ");
        }
    }


    public class RealProxy : IReal
    {
        IReal real = new Real();

        public void DoWork()
        {
            real.DoWork();
        }
    }

    /*Adapter*/

    public interface IActual
    {
        void DoWork();
    }

    public class Api
    {
        public void SomeApi(IActual actual)
        {
            actual.DoWork();
        }
    }

    public interface IInHand
    {
        void DoWorkDifferently();
    }

    public class InHand : IInHand
    {
        public void DoWorkDifferently()
        {
            Console.WriteLine("doing work slightly different ");
        }
    }

    public class ActualAdapterForInHand : IActual
    {
        IInHand hand = null;

        public ActualAdapterForInHand()
        {
            hand = new InHand();
        }

        public ActualAdapterForInHand(IInHand hnd)
        {
            hand = hnd;
        }

        public void DoWork()
        {
            hand.DoWorkDifferently();
        }
    }

    /*Decorator*/

    public interface IReady
    {
        void GetReady();
    }

    public class Male : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
        }
    }

    public class Female : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
            Console.WriteLine("Make up....");
        }
    }

    //this is a decorator
    public class Beautician : IReady
    {
        IReady ready = null;

        public Beautician(IReady rdy)
        {
            ready = rdy;
        }

        public void GetReady()
        {
            ready.GetReady();
            Console.WriteLine("Style hair ");

            if (ready is Female)
            {
                for (int i = 1; i <= 10; i++)
                {
                    Console.WriteLine("doing ready process " + i);
                }

            }
        }
    }

}

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

следовательно сконцентрируйте больше на твердых принципах desighn, чистых принципах кодирвоания и ttd