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

StackOverflow https://stackoverflow.com/questions/319728

  •  11-07-2019
  •  | 
  •  

Вопрос

Кто-нибудь когда-нибудь пользовался Узор Моста в реальном приложении?Если да, то как вы его использовали?Мне кажется, или это просто шаблон адаптера с небольшим внедрением зависимостей, добавленный в смесь?Действительно ли она заслуживает своего собственного образца?

Это было полезно?

Решение

Классический пример шаблона Bridge используется в определении фигур в среде пользовательского интерфейса (см. мост шаблон википедии ). Шаблон Мост является составным из < a href = "http://en.wikipedia.org/wiki/Template_method_pattern" rel = "noreferrer"> Шаблон и Шаблоны стратегии .

Это общий вид некоторых аспектов шаблона Adapter в шаблоне Bridge. Однако, чтобы процитировать эту статью :

  

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

Другие советы

Существует комбинация следующих факторов У Федерико и У Джона ответы.

Когда:

                   ----Shape---
                  /            \
         Rectangle              Circle
        /         \            /      \
BlueRectangle  RedRectangle BlueCircle RedCircle

Рефакторинг для:

          ----Shape---                        Color
         /            \                       /   \
Rectangle(Color)   Circle(Color)           Blue   Red

Шаблон Bridge является приложением старого совета, «предпочитаю композицию, а не наследование». Это становится удобным, когда вы должны создавать подклассы разного времени способами, которые ортогональны друг другу. Скажем, вы должны реализовать иерархию цветных фигур. Вы бы не создали подкласс Shape с Rectangle и Circle, а затем создали бы подкласс Rectangle с RedRectangle, BlueRectangle и GreenRectangle и то же самое для Circle, не так ли? Вы бы предпочли сказать, что у каждого Shape есть цвет, и для реализации иерархии цветов, и это паттерн моста. Ну, я бы не реализовал "иерархию цветов", но вы поняли ...

Когда:

        A
     /     \
    Aa      Ab
   / \     /  \
 Aa1 Aa2  Ab1 Ab2

Рефакторинг для:

     A         N
  /     \     / \
Aa(N) Ab(N)  1   2

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

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

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

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

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

См. также http://c2.com/cgi/wiki?BridgePattern

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

И совет: всегда думайте о шаблонах дизайна с концептуальной точки зрения , а не с точки зрения реализации. С правильной точки зрения Bridge нельзя спутать с Adapter, потому что они решают другую проблему, а композиция превосходит наследование не потому, что она сама по себе, а потому, что она позволяет обрабатывать ортогональные задачи отдельно.

Намерение Мост и Адаптер это разные модели, и нам нужны оба паттерна по отдельности.

Узор моста:

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

Используйте шаблон моста, когда:

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

Ответ @ John Sonmez ясно показывает эффективность шаблона bridge в уменьшении иерархии классов.

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

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

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

Ключевые отличия:

  1. Адаптер заставляет вещи работать после того, как они разработаны; Мост заставляет их работать до того, как они появятся.
  2. Мост разработан заранее, чтобы позволить абстракция и реализация варьируются независимо. Адаптер модифицирован таким образом, чтобы заставить несвязанные классы работать вместе.
  3. Намерение : Адаптер позволяет двум несвязанным интерфейсам работать вместе. Мост позволяет абстракции и реализации изменяться независимо.

Связанный с SE вопрос с UML-схемой и рабочим кодом:

Разница между мостовой схемой и Адаптерной схемой

Полезные статьи:

мост для создания источника выкройка изделия

адаптер для создания исходного кода выкройка изделия

мост журнальдева выкройка изделия

Редактировать:

Пример шаблона моста из реального мира (согласно meta.stackoverflow.com предложению, включил пример сайта документации в этот пост, поскольку документация будет закрыта)

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

Шаблон моста UML из Википедии:

Bridge pattern UML from Wikipedia

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

Abstraction:Он определяет интерфейс

RefinedAbstraction:Он реализует абстракцию:

Implementor:Он определяет интерфейс для реализации

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

The crux of Bridge pattern : Две ортогональные иерархии классов с использованием композиции (и без наследования).Иерархия абстракции и иерархия реализации могут варьироваться независимо.Реализация никогда не ссылается на Абстракцию.Абстракция содержит интерфейс реализации в качестве элемента (через композицию).Такая композиция уменьшает еще один уровень иерархии наследования.

Реальный вариант употребления слова:

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

Пример кода:

/* Implementor interface*/
interface Gear{
    void handleGear();
}

/* Concrete Implementor - 1 */
class ManualGear implements Gear{
    public void handleGear(){
        System.out.println("Manual gear");
    }
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
    public void handleGear(){
        System.out.println("Auto gear");
    }
}
/* Abstraction (abstract class) */
abstract class Vehicle {
    Gear gear;
    public Vehicle(Gear gear){
        this.gear = gear;
    }
    abstract void addGear();
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
    public Car(Gear gear){
        super(gear);
        // initialize various other Car components to make the car
    }
    public void addGear(){
        System.out.print("Car handles ");
        gear.handleGear();
    }
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
    public Truck(Gear gear){
        super(gear);
        // initialize various other Truck components to make the car
    }
    public void addGear(){
        System.out.print("Truck handles " );
        gear.handleGear();
    }
}
/* Client program */
public class BridgeDemo {    
    public static void main(String args[]){
        Gear gear = new ManualGear();
        Vehicle vehicle = new Car(gear);
        vehicle.addGear();

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

        gear = new ManualGear();
        vehicle = new Truck(gear);
        vehicle.addGear();

        gear = new AutoGear();
        vehicle = new Truck(gear);
        vehicle.addGear();
    }
}

выходной сигнал:

Car handles Manual gear
Car handles Auto gear
Truck handles Manual gear
Truck handles Auto gear

Объяснение:

  1. Vehicle это абстракция.
  2. Car и Truck существуют две конкретные реализации Vehicle.
  3. Vehicle определяет абстрактный метод : addGear().
  4. Gear является интерфейсом разработчика
  5. ManualGear и AutoGear существуют две реализации Gear
  6. Vehicle содержит implementor интерфейс, а не реализация интерфейса. Compositon интерфейс разработчика - суть этого шаблона : Это позволяет абстракции и реализации варьироваться независимо.
  7. Car и Truck определите реализацию (переопределенную абстракцию) для абстракции : addGear() :Он содержит Gear - Либо Manual или Auto

Варианты использования для шаблона моста:

  1. Абстракция и Реализация могут меняться независимо друг от друга, и они не связаны во время компиляции
  2. Отображение ортогональных иерархий - Одно для Абстракция и один для Реализация.

Я использовал шаблон моста на работе. Я программирую на C ++, где его часто называют идиомой PIMPL (указатель на реализацию). Это выглядит так:

class A
{
public: 
  void foo()
  {
    pImpl->foo();
  }
private:
  Aimpl *pImpl;
};

class Aimpl
{
public:
  void foo();
  void bar();
};  

В этом примере класс A содержит интерфейс, а класс Aimpl содержит реализацию.

Одним из применений этого шаблона является предоставление только некоторых открытых членов класса реализации, но не других. В этом примере только Aimpl :: foo () можно вызвать через открытый интерфейс A , но не Aimpl :: bar ()

Еще одним преимуществом является то, что вы можете определить Aimpl в отдельном заголовочном файле, который не должен быть включен пользователями A . Все, что вам нужно сделать, это использовать предварительное объявление Aimpl до определения A и переместить определения всех функций-членов, ссылающихся на pImpl , в файл .cpp. Это дает вам возможность сохранять частный заголовок Aimpl и сокращать время компиляции.

Чтобы поместить пример формы в код:

#include<iostream>
#include<string>
#include<cstdlib>

using namespace std;

class IColor
{
public:
    virtual string Color() = 0;
};

class RedColor: public IColor
{
public:
    string Color()
    {
        return "of Red Color";
    }
};

class BlueColor: public IColor
{
public:
    string Color()
    {
        return "of Blue Color";
    }
};


class IShape
{
public:
virtual string Draw() = 0;
};

class Circle: public IShape
{
        IColor* impl;
    public:
        Circle(IColor *obj):impl(obj){}
        string Draw()
        {
            return "Drawn a Circle "+ impl->Color();
        }
};

class Square: public IShape
{
        IColor* impl;
    public:
        Square(IColor *obj):impl(obj){}
        string Draw()
        {
        return "Drawn a Square "+ impl->Color();;
        }
};

int main()
{
IColor* red = new RedColor();
IColor* blue = new BlueColor();

IShape* sq = new Square(red);
IShape* cr = new Circle(blue);

cout<<"\n"<<sq->Draw();
cout<<"\n"<<cr->Draw();

delete red;
delete blue;
return 1;
}

Вывод:

Drawn a Square of Red Color
Drawn a Circle of Blue Color

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

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

Bridge design pattern we can easily understand helping of service and dao layer.

Dao layer -> create common interface for dao layer ->
public interface Dao<T>{
void save(T t);
}
public class AccountDao<Account> implement Dao<Account>{
public void save(Account){
}
}
public LoginDao<Login> implement Dao<Login>{
public void save(Login){
}
}
Service Layer ->
1) interface
public interface BasicService<T>{
    void save(T t);
}
concrete  implementation of service -
Account service -
public class AccountService<Account> implement BasicService<Account>{
 private Dao<Account> accountDao;
 public AccountService(AccountDao dao){
   this.accountDao=dao;
   }
public void save(Account){
   accountDao.save(Account);
 }
}
login service- 
public class LoginService<Login> implement BasicService<Login>{
 private Dao<Login> loginDao;
 public AccountService(LoginDao dao){
   this.loginDao=dao;
   }
public void save(Login){
   loginDao.save(login);
 }
}

public class BridgePattenDemo{
public static void main(String[] str){
BasicService<Account> aService=new AccountService(new AccountDao<Account>());
Account ac=new Account();
aService.save(ac);
}
}
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top