Różnica między wzorem mostka a wzorem adaptera


125

Jaka jest różnica między wzorcami mostka i adaptera?


Może rozważ zaproponowanie edycji wyjaśniającej, która poprowadzi dyskusję na temat tego, gdzie Twoim zdaniem należy użyć jednego lub drugiego.
Jeff Wilcox,


Odpowiedzi:


173

„Adapter sprawia, że ​​rzeczy działają po ich zaprojektowaniu; Bridge sprawia, że ​​działają, zanim się pojawią. [GoF, p219]”

W rzeczywistości wzorzec adaptera jest przydatny, gdy masz istniejący kod, niezależnie od tego, czy jest to strona trzecia, czy wewnętrzny, ale poza twoją kontrolą lub w inny sposób nie można go zmienić, aby całkowicie dopasować się do interfejsu, do którego go potrzebujesz. Na przykład mamy tablicę SuperWeaponsArray, która może sterować szeroką gamą urządzeń zagłady.

public class SuperWeaponsArray {
  /*...*/

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

Wspaniały. Z tym, że zdajemy sobie sprawę, że mamy w naszym arsenale urządzenie jądrowe, które znacznie wyprzedziło przejście na interfejs broni. Ale naprawdę chcielibyśmy, żeby to działało ... więc co robimy ... wciskamy to!

NukeWeaponsAdaptor - oparty na naszej klasie Nuke, ale eksportujący interfejs Weapon. Słodko, teraz z pewnością możemy zniszczyć świat. Wydaje się, że to trochę niezdarne, ale sprawia, że ​​wszystko działa.


Most wzór jest coś wdrożyć z przodu - jeśli wiesz, że masz dwie prostopadłe hierarchie, zapewnia sposób oddzielić interfejs i wdrożenie w taki sposób, aby nie uzyskać numer insane klas. Powiedzmy, że masz:

MemoryMappedFile i DirectReadFile obiektów plików. Powiedzmy, że chcesz mieć możliwość odczytywania plików z różnych źródeł (może implementacje Linux vs. Windows itp.). Bridge pomaga uniknąć likwidacji z:

MemoryMappedWindowsFile MemoryMappedLinuxFile DirectReadWindowsFile DirectReadLinuxFile


9
odrzucony, czy mógłbyś użyć bardziej abstrakcyjnego wykazu kodu? przykład jest zbyt szczegółowy i mylący.

36
@omouse upvoted, przykładowy kod naprawdę nie jest tym, co sprawia, że ​​ta odpowiedź jest konkretna . Dla uważnego czytelnika jest wystarczająco dużo wskazówek, aby zacząć rozróżniać wzorce, więc w sumie jest to dobra odpowiedź.
Victor Farazdagi,

15
czy możesz podać przykładowy kod dla wzorca mostu?
Jaime Hablutzel

2
Wyobrażam sobie, że wielu ludzi podeszło do tego pytania w ten sam sposób, co ja - prawdopodobnie już patrzyli na kod dla tych dwóch wzorców, ale zauważyli pewne podobieństwa i zdali sobie sprawę, że ich zrozumienie może zostać dodatkowo wzmocnione poprzez zestawienie dwóch wzorców. Fragment o mostku, który pomaga uniknąć zamykania się z plikami specyficznymi dla systemów Windows i Linux, był, przynajmniej dla mnie, instrumentalny w zrozumieniu, w jaki sposób „implementator” wzorca mostu ( dofactory.com/net/bridge-design-pattern ) różni się od "Adapter".
Jordan,

3
„Adapter sprawia, że ​​rzeczy działają po ich zaprojektowaniu; Bridge sprawia, że ​​działają, zanim się pojawią”. nie zostało w ogóle wymienione w książce, którą czytałem, więc trudno było je rozróżnić.
Wydaje

15

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

Wzorzec adaptera polega bardziej na uzyskaniu istniejącego kodu do pracy z nowszym systemem lub interfejsem.

Jeśli masz zestaw interfejsów API usług sieciowych będących standardem firmy, które chciałbyś zaoferować istniejącemu interfejsowi rozszerzalności innej aplikacji, możesz rozważyć napisanie zestawu adapterów do tego. Zwróć uwagę, że istnieje szara strefa i chodzi bardziej o to, jak technicznie definiujesz wzór, ponieważ inne wzory, takie jak fasada, są podobne.

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

Wzorzec Bridge pozwoli ci ewentualnie mieć alternatywne implementacje algorytmu lub systemu.

Chociaż nie jest to klasyczny przykład wzorca Bridge, wyobraź sobie, że masz kilka implementacji magazynu danych: jedna jest wydajna w przestrzeni, druga jest wydajna w surowej wydajności ... i masz uzasadnienie biznesowe, aby oferować zarówno w swojej aplikacji, jak i frameworku .

Jeśli chodzi o twoje pytanie, „gdzie mogę użyć jakiego wzoru”, odpowiedź brzmi: gdziekolwiek ma to sens dla twojego projektu! Być może rozważ zaproponowanie edycji wyjaśniającej, która poprowadzi dyskusję na temat tego, gdzie Twoim zdaniem należy użyć jednego lub drugiego.


14

Adapter:

  1. Jest to wzór strukturalny
  2. Przydaje się praca z dwoma niekompatybilnymi interfejsami

Diagram UML: z artykułu dofactory :

wprowadź opis obrazu tutaj

Cel : definiuje specyficzny dla domeny interfejs, z którego korzysta Klient.

Adapter : dostosowuje interfejs Adaptee do interfejsu docelowego.

Adaptee : definiuje istniejący interfejs, który wymaga dostosowania.

Klient : współpracuje z obiektami zgodnymi z interfejsem Target.

Przykład:

Kwadrat i Prostokąt to dwa różne kształty, a uzyskanie pola powierzchni () każdego z nich wymaga innych metod. Ale nadal Square działa na interfejsie Rectangle z konwersją niektórych właściwości.

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

Most:

  1. To wzór strukturalny
  2. oddziela abstrakcję od jej implementacji i obie mogą się zmieniać niezależnie
  3. Jest to możliwe, ponieważ zamiast dziedziczenia zastosowano kompozycję

EDYTUJ: (zgodnie z sugestią @quasoft)

W tym wzorze masz cztery komponenty.

  1. Abstrakcja : definiuje interfejs

  2. RefinedAbstraction : Implementuje abstrakcję:

  3. Implementator : definiuje interfejs do implementacji

  4. ConcreteImplementor : implementuje interfejs Implementor.

Fragment kodu:

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

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

Powiązany post:

Kiedy używasz wzoru mostka? Czym różni się od wzoru adaptera?

Kluczowe różnice: od artykułu źródłowego

  1. Adapter sprawia, że ​​wszystko działa po ich zaprojektowaniu; Bridge sprawia, że ​​działają, zanim oni.
  2. Bridge jest zaprojektowany z góry, aby abstrakcja i implementacja różniły się niezależnie. Adapter jest zmodernizowany, aby niepowiązane klasy współpracowały.

Uwzględnij przykład samochodu / ciężarówki / przekładni z dokumentów w odpowiedzi. Świetny przykład i analogia.
quasoft

8

Ten post istnieje już od dłuższego czasu. Jednak ważne jest, aby zrozumieć, że fasada jest nieco podobna do adaptera, ale to nie to samo. Adapter „dostosowuje” istniejącą klasę do zwykle niekompatybilnej klasy klienta. Załóżmy, że masz stary system przepływu pracy, którego aplikacja używa jako klienta. Twoja firma mogłaby ewentualnie wymienić system workflow na nowy „niekompatybilny” (pod względem interfejsów). W większości przypadków można użyć wzorca adaptera i napisać kod, który faktycznie wywołuje interfejsy nowego silnika przepływu pracy. Most jest generalnie używany w inny sposób. Jeśli faktycznie masz system, który musi współpracować z różnymi systemami plików (np. Dysk lokalny, NFS itp.), Możesz użyć wzorca mostu i utworzyć jedną warstwę abstrakcji do pracy ze wszystkimi systemami plików. Byłby to w zasadzie prosty przypadek użycia wzorca mostka. Fasada i adapter mają wspólne właściwości, alefasady są zwykle używane w celu uproszczenia istniejącego interfejsu / klasy . We wczesnych dniach EJB nie było lokalnych wezwań do EJB. Programiści zawsze uzyskiwali kod pośredniczący, zawężali go i nazywali „pseudo-zdalnie”. Często powodowało to problemy z wydajnością (zwłaszcza, gdy naprawdę było wywoływane przez kabel). Doświadczeni programiści używali wzoru elewacji, aby zapewnić klientowi bardzo gruboziarnisty interfejs. Ta fasada z kolei powodowałaby wielokrotne wywoływanie różnych, bardziej precyzyjnych metod. Podsumowując, znacznie zmniejszyło to liczbę wymaganych wywołań metod i zwiększyło wydajność.


Chociaż, pozornie poza zakresem tego pytania, ważenie adaptera i mostka względem fasady może być bardzo odpowiednie.
Cody,

1

Most jest ulepszonym adapterem. Bridge zawiera adapter i zapewnia mu dodatkową elastyczność. Oto jak elementy z odpowiedzi Ravindry mapują się między wzorcami:

      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

W górnej odpowiedzi @James cytuje zdanie z GoF, strona 219. Myślę, że warto przytoczyć tutaj pełne wyjaśnienie.

Adapter a mostek

Wzorce Adapter i Bridge mają pewne wspólne atrybuty. Oba promują elastyczność, zapewniając poziom pośredni względem innego obiektu. Oba obejmują przekazywanie żądań do tego obiektu z interfejsu innego niż jego własny.

Kluczowa różnica między tymi wzorcami polega na ich intencjach. Adapter koncentruje się na rozwiązywaniu niezgodności między dwoma istniejącymi interfejsami. Nie koncentruje się na tym, jak te interfejsy są zaimplementowane, ani nie rozważa, jak mogą ewoluować niezależnie. Jest to sposób na sprawienie, aby dwie niezależnie zaprojektowane klasy współpracowały ze sobą bez konieczności ponownego wdrażania jednej lub drugiej. Z drugiej strony, most łączy abstrakcję i jej (potencjalnie liczne) implementacje. Zapewnia stabilny interfejs dla klientów, nawet jeśli umożliwia zróżnicowanie klas, które go implementują. Obsługuje również nowe implementacje w miarę rozwoju systemu.

W wyniku tych różnic adapter i mostek są często używane na różnych etapach cyklu życia oprogramowania. Adapter często staje się konieczny, gdy odkryjesz, że dwie niezgodne klasy powinny ze sobą współpracować, zazwyczaj w celu uniknięcia replikacji kodu. Sprzężenie jest nieprzewidziane. W przeciwieństwie do tego, użytkownik mostu rozumie z góry, że abstrakcja musi mieć kilka implementacji i obie mogą ewoluować niezależnie. Wzorzec Adapter sprawia, że ​​rzeczy działają po ich zaprojektowaniu; Bridge sprawia, że ​​działają, zanim oni. Nie oznacza to, że Adapter jest w jakiś sposób gorszy od Bridge; każdy wzorzec dotyczy jedynie innego problemu.


0

Załóżmy, że masz abstrakcyjną klasę Shape z (ogólną / abstrakcyjną) funkcją rysowania i Circle, która implementuje Shape. Wzorzec mostu to po prostu dwukierunkowa abstrakcja, która polega na oddzieleniu implementacji (rysowanie w okręgu) od funkcjonalności ogólnej / abstrakcyjnej (rysowanie w klasie Shape).

Co to naprawdę oznacza? Na pierwszy rzut oka brzmi to jak coś, co już tworzysz (przez odwrócenie zależności). Więc nie martw się o mniej sztywną lub bardziej modułową bazę kodu. Ale kryje się za tym nieco głębsza filozofia.

Z mojego rozumienia potrzeba wzorca użycia może pojawić się, gdy potrzebuję dodać nowe klasy, które są ściśle związane z obecnym systemem (jak RedCircle lub GreenCircle) i które różnią się tylko jedną funkcjonalnością (jak kolor). I będę potrzebować wzorca Bridge, szczególnie jeśli istniejące klasy systemowe (Circle lub Shape) mają być często zmieniane i nie chcesz, aby zmiany te miały wpływ na nowo dodane klasy. Dlatego też ogólna funkcja rysowania została przeniesiona do nowego interfejsu, dzięki czemu można zmieniać zachowanie rysowania niezależnie od kształtu lub okręgu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.