Как отличаются параметры прокси, декоратора, адаптера и моста?

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

Мое занятие по теме.

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

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

Адаптер

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

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

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

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

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

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

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

декоратор

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

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

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

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

Proxy

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

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

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

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

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

Фасад

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

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

Мост

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

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

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

  • Прокси не переносит существующий объект. В конструкторе нет объекта.

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

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

Пример реальной жизни - JAXB Marshalling Adapter. Цель этого адаптера - сопоставление простого плоского класса с более сложной структурой, требуемой извне, и предотвращение "загрязняющих" предметных классов чрезмерными аннотациями.

Ответ 4

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

Мое понимание шаблонов увеличилось в 100 раз после прочтения Начать первые шаблоны дизайна.

Я очень рекомендую!

Ответ 5

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

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

Decorator:

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

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

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

Прокси-сервер:

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

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

Adapter:

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

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

Мост:

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

например. Коллекционные классы в java.util. List реализовано ArrayList.

Ключевые примечания:

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

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

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

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

Различия между шаблоном Proxy и Decorator

Ответ 6

Они очень похожи, а линии между ними довольно серые. Я предлагаю вам прочитать прокси-шаблон и Decorator Pattern записи в c2 wiki.

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

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

Ответ 7

Это цитата из Начать первые шаблоны дизайна

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

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

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

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

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

Ответ 8

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

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

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

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

Ответ 9

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

Ответ 10

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

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

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

Ответ 11

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

Цитированные части - это ответ [fooobar.com/questions/20008/... (Bill Karwing)

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

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

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 { ... }
  • Decorator также называется "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 { ... }
  • Адаптер используется, когда у вас есть абстрактный интерфейс, и вы хотите сопоставить этот интерфейс с другим объектом, который имеет аналогичный функциональный роль, но другой интерфейс.

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

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

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

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

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

Ответ 12

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

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);
                }

            }
        }
    }

}

Ответ 13

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

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