Разница между шаблоном моста и шаблоном адаптера

126

В чем разница между шаблонами "Мост" и "Адаптер"?

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

Ответы:

173

«Адаптер заставляет вещи работать после того, как они спроектированы; Bridge заставляет их работать раньше, чем они есть. [GoF, p219]»

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

public class SuperWeaponsArray {
  /*...*/

  public void destroyWorld() {
    for (Weapon w : armedWeapons) {
      w.fire();
    }
  }
}

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

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


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

Типы файловых объектов MemoryMappedFile и DirectReadFile. Допустим, вы хотите иметь возможность читать файлы из различных источников (возможно, Linux или Windows и т. Д.). Bridge поможет вам избежать:

MemoryMappedWindowsFile MemoryMappedLinuxFile DirectReadWindowsFile DirectReadLinuxFile

Джеймс
источник
9
проголосовали против, не могли бы вы использовать более абстрактный листинг кода? пример слишком конкретен и сбивает с толку.
36
@omouse проголосовал за, пример кода на самом деле не то, что делает этот ответ точным . Для бережного читателя есть достаточное количество указателей , чтобы начать различать узоры, так что все во всем - это есть хороший ответ.
Victor Farazdagi
15
не могли бы вы предоставить какой-нибудь реальный пример кода для шаблона моста?
Хайме Хаблутцель
2
Я полагаю, что многие люди пришли к этому вопросу так же, как и я - они, вероятно, уже рассматривали код для двух шаблонов, но признали некоторые сходства и поняли, что их понимание может быть дополнительно укреплено путем сопоставления двух шаблонов. Строка о мосте, который поможет вам избежать использования файлов, специфичных для Windows и Linux, сыграла, по крайней мере, для меня, способствующую пониманию того, чем "Реализователь" шаблона моста ( dofactory.com/net/bridge-design-pattern ) отличается от шаблона «адаптер».
Jordan
3
«Адаптер заставляет вещи работать после того, как они спроектированы; Bridge заставляет их работать раньше, чем они есть». в книге, которую я прочитал, вообще не было указано, поэтому их было трудно отличить. Думаю, чтение GOF в конце концов стоит усилий ...
Александр Дерк
15

http://en.wikipedia.org/wiki/Adapter_pattern

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

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

http://en.wikipedia.org/wiki/Bridge_pattern

Шаблон «Мост» позволит вам, возможно, иметь альтернативные реализации алгоритма или системы.

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

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

Джефф Уилкокс
источник
14

адаптер:

  1. Это структурный образец
  2. Полезно работать с двумя несовместимыми интерфейсами

Диаграмма UML: из внутренней статьи:

введите описание изображения здесь

Target : определяет интерфейс для домена, который использует Клиент.

Адаптер : адаптирует интерфейс адаптируемого к целевому интерфейсу.

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

Клиент : взаимодействует с объектами, соответствующими интерфейсу Target.

Пример:

Квадрат и Прямоугольник - это две разные формы, и получение area () каждой из них требует разных методов. Но все же Square работает над интерфейсом Rectangle с преобразованием некоторых свойств.

public class AdapterDemo{
    public static void main(String args[]){
        SquareArea s = new SquareArea(4);
        System.out.println("Square area :"+s.getArea());
    }
}

class RectangleArea {
    public int getArea(int length, int width){
        return length * width;
    }
}

class SquareArea extends RectangleArea {

    int length;
    public SquareArea(int length){
        this.length = length;
    }
    public int getArea(){
        return getArea(length,length);
    }
}

мост:

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

РЕДАКТИРОВАТЬ: (согласно предложению @quasoft)

У вас есть четыре компонента в этом шаблоне.

  1. Абстракция : определяет интерфейс

  2. RefinedAbstraction : реализует абстракцию:

  3. Разработчик : определяет интерфейс для реализации.

  4. ConcreteImplementor : он реализует интерфейс разработчика.

Фрагмент кода:

Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();

gear = new AutoGear();
vehicle = new Car(gear);
vehicle.addGear();

Связанный пост:

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

Ключевые отличия: из исходной статьи

  1. Адаптер заставляет вещи работать после того, как они спроектированы; Мост заставляет их работать раньше, чем они есть.
  2. Мост разработан заранее, чтобы абстракция и реализация менялись независимо. Адаптер модернизирован для совместной работы несвязанных классов.
Равиндра бабу
источник
Включите в ответ пример автомобиля / грузовика / снаряжения из документации. Отличный пример и аналогия.
quasoft
8

Этот пост существует довольно давно. Однако важно понимать, что фасад чем-то похож на адаптер, но это не совсем то же самое. Адаптер «адаптирует» существующий класс к обычно несовместимому клиентскому классу. Допустим, у вас есть старая система рабочих процессов, которую ваше приложение использует в качестве клиента. Возможно, ваша компания заменит систему документооборота на новую «несовместимую» (с точки зрения интерфейсов). В большинстве случаев вы можете использовать шаблон адаптера и написать код, который фактически вызывает интерфейсы нового механизма рабочего процесса. Мост обычно используется иначе. Если у вас действительно есть система, которая должна работать с разными файловыми системами (например, локальный диск, NFS и т. Д.), Вы можете использовать шаблон моста и создать один уровень абстракции для работы со всеми вашими файловыми системами. По сути, это был бы простой вариант использования шаблона моста. Фасад и адаптер имеют общие свойства, нофасады обычно используются для упрощения существующего интерфейса / класса . В первые дни EJB не было местных вызовов для EJB. Разработчики всегда получали заглушку, сужали ее и называли «псевдо-удаленно». Это часто приводило к проблемам с производительностью (особенно при вызове по сети). Опытные разработчики могли бы использовать паттерн фасада, чтобы предоставить клиенту очень крупнозернистый интерфейс. Этот фасад, в свою очередь, будет выполнять несколько вызовов различных более тонких методов. В целом это значительно сократило количество требуемых вызовов методов и повысило производительность.

Джон Пеннер
источник
Хотя, казалось бы, за рамками этого вопроса, взвешивание адаптера и моста против фасада может быть очень уместным.
Cody
1

Мост улучшен Адаптер. Bridge включает адаптер и добавляет ему дополнительную гибкость. Вот как элементы из карты ответов Равиндры между шаблонами:

      Adapter  |    Bridge
    -----------|---------------
    Target     | Abstraction
    -----------|---------------
               | RefinedAbstraction
               |
               |   This element is Bridge specific. If there is a group of 
               |   implementations that share the same logic, the logic can be placed here.
               |   For example, all cars split into two large groups: manual and auto. 
               |   So, there will be two RefinedAbstraction classes.
    -----------|--------------- 
    Adapter    | Implementor
    -----------|---------------
    Adaptee    | ConcreteImplementor
полина-с
источник
1

В верхнем ответе @James цитирует предложение из GoF, стр. 219. Я думаю, что стоит воспроизвести здесь полное объяснение.

Адаптер против моста

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

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

В результате этих различий адаптер и мост часто используются на разных этапах жизненного цикла программного обеспечения. Адаптер часто становится необходимым, когда вы обнаруживаете, что два несовместимых класса должны работать вместе, как правило, чтобы избежать репликации кода. Муфта непредвиденная. Напротив, пользователь моста заранее понимает, что абстракция должна иметь несколько реализаций, и обе могут развиваться независимо. Шаблон адаптера заставляет вещи работать после того, как они спроектированы; Мост заставляет их работать раньше, чем они есть. Это не значит, что Adapter чем-то уступает Bridge; каждый шаблон просто обращается к другой проблеме.

jaco0646
источник
0

Предположим, у вас есть абстрактный класс Shape с (общей / абстрактной) функцией рисования и Circle, который реализует Shape. Шаблон моста - это просто двухсторонний абстракционный подход, позволяющий разделить реализацию (рисование в круге) и общие / абстрактные функции (рисование в классе Shape).

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

Насколько я понимаю, необходимость в шаблоне использования может возникнуть, когда мне нужно добавить новые классы, которые тесно связаны с текущей системой (например, RedCircle или GreenCircle) и которые отличаются только одной функциональностью (например, цветом). И мне понадобится шаблон Bridge, особенно если существующие системные классы (Circle или Shape) должны часто изменяться, и вы не хотите, чтобы эти изменения влияли на вновь добавленные классы. Вот почему общие функции рисования абстрагируются в новом интерфейсе, чтобы вы могли изменять поведение рисования независимо от формы или круга.

стандартный вывод
источник