Розуміння схеми дизайну моста


24

Я взагалі не розумію схему дизайну «містків». Я переглянув різні веб-сайти, але вони не допомогли.

Хтось може мені допомогти в розумінні цього?


2
Я теж цього не розумію. З нетерпінням чекаю відповіді :)
Фіолетовий Жирафа

Існує багато веб-сайтів і книг, що описують шаблони дизайну. Я не думаю, що є значення в повторенні того, що вже написано, можливо, ви можете задати конкретне запитання. Мені знадобився певний час, щоб зрозуміти це, продовжуючи перемикатися між різними джерелами та прикладами.
Олена

Відповіді:


16

У ООП ми використовуємо поліморфізм, тому абстракція може мати кілька реалізацій. Давайте розглянемо наступний приклад:

//trains abstraction
public interface Train
{ 
    move();
}
public class MonoRail:Train
{
    public override move()
    {
        //use one track;
    }
}
public class Rail:Train
{
    public override move()
    {
        //use two tracks;
    }
}

Нова вимога, яка запроваджена та має враховувати перспективу прискорення поїздів, тому змініть код, як показано нижче.

    public interface Train
    { 
        void move();
    }
    public class MonoRail:Train
    {
        public override void move()
        {
            //use one track;
        }
    }
    public class ElectricMonoRail:MonoRail
    {
        public override void move()
        {
            //use electric engine on one track.
        }
    }
    public class DieselMonoRail: MonoRail
    {
        public override void move()
        {
            //use diesel engine on one track.
        }
    }
    public class Rail:Train
    {
        public override void move()
        {
            //use two tracks;
        }
    }
    public class ElectricRail:Rail
    {
        public override void move()
        {
            //use electric engine on two tracks.
        }
    }
    public class DieselRail: Rail
    {
        public override void move()
        {
            //use diesel engine on two tracks.
        }
    }

Вищевказаний код не є ретельним і не потребує повторного використання (якщо припустити, що ми могли б використати механізм прискорення для тієї ж платформи треку). У наведеному нижче коді застосовується схема мосту і розділяє дві різні абстракції, транспорт поїздів та прискорення .

public interface Train
{ 
    void move(Accelerable engine);
}
public interface Accelerable
{
    public void accelerate();
}
public class MonoRail:Train
{
    public override void move(Accelerable engine)
    {
        //use one track;
        engine.accelerate(); //engine is pluggable (runtime dynamic)
    }
}
public class Rail:Train
{
    public override void move(Accelerable engine)
    {
        //use two tracks;
        engine.accelerate(); //engine is pluggable (runtime dynamic)
    }
}
public class ElectricEngine:Accelerable{/*implementation code for accelerable*/}
public class DieselEngine:Accelerable{/*implementation code for accelerable*/}

3
Дуже приємний приклад. Я додам свої два центи: це дуже хороший приклад переваги композиції над спадщиною
zzfima

1
Для чого це варто, я думаю, що так має бути, Monorailоскільки це насправді не два слова, це одне (складене) слово. MonoRail був би деяким підкласом Rail замість іншого виду залізниць (яким він є). Так само , як ми не будемо використовувати SunShineабо CupCakeвони були б SunshineіCupcake
ErikE

Цей рядок "дві різні абстракції, транспорт поїздів і прискорення" допомагає вказати, що є двома ієрархіями, і що ми намагаємося вирішити, це зробити їх різними незалежно.
wangdq

11

Хоча більшість моделей дизайну мають корисні назви, я вважаю, що ім'я "Bridge" не інтуїтивно зрозуміло, чим він займається.

Концептуально ви висуваєте деталі реалізації, використовувані ієрархією класів, в інший об'єкт, як правило, з власною ієрархією. Тим самим ви знімаєте жорстку залежність від цих деталей реалізації та дозволяєте змінювати деталі цієї реалізації.

Невеликим масштабом я порівнюю це із застосуванням стратегії в тому, як можна підключити нову поведінку. Але замість просто обгортання алгоритму, як це часто спостерігається в стратегії, об'єкт реалізації, як правило, заповнюється більше функцій. І коли ви застосовуєте цю концепцію до цілої ієрархії класів, більший зразок стає містком. (Знову ненавиджу ім’я).

Це не той шаблон, яким ви будете користуватися щодня, але я вважаю це корисним при управлінні потенційним вибухом класів, який може статися, коли у вас є (очевидна) потреба у багатократному успадкуванні.

Ось приклад із реального світу:

У мене є інструмент RAD, який дозволяє вам скидати та налаштовувати елементи керування на проектній поверхні, тому у мене є така об'єктна модель:

Widget // base class with design surface plumbing
+ Top
+ Left
+ Width
+ Height
+ Name
+ SendToBack
+ BringToFront
+ OnPropertyEdit
+ OnSelect
+ Validate
+ ShowEditor
+ Paint
+ Etc

TextboxWidget : Widget // text box specific
+ Text
+ MaxLength
+ Font
+ ShowEditor // override base to show a property editor form specific to a Textbox
+ Paint // override to render a textbox onto the surface    
+ Etc

ListWidget : Widget // list specific
+ Items
+ SelectedItem
+ ShowEditor // override base to show a property editor form specific to a List
+ Paint // override to render a list onto the surface
+ Etc

І так далі, можливо, з десяток контролів.

Але потім додається нова вимога для підтримки декількох тем (look-n-feel). Скажімо , у нас є такі теми: Win32, WinCE, WinPPC, WinMo50, WinMo65. Кожна тема матиме різні значення або реалізації для операцій, пов’язаних з візуалізацією, таких як DefaultFont, DefaultBackColor, BorderWidth, DrawFrame, DrawScrollThumb тощо.

Я можу створити подібну об'єктну модель:

Win32TextboxWidget : TextboxWidget

Win32ListWidget : ListWidget

тощо, для одного типу керування

WinCETextboxWidget : TextboxWidget

WinCEListWidget : ListWidget

і т.д., для кожного іншого типу управління (знову)

Ви отримуєте ідею - ви отримуєте класовий вибух числа віджетів, разів більше # тем. Це ускладнює дизайнера RAD, даючи йому знати про кожну тему. Крім того, додавання нових тем примушує модифікацію дизайнера RAD. Крім того, існує багато спільної реалізації в рамках теми, яку було б чудово успадкувати, але елементи керування вже успадковують із загальної бази ( Widget).

Тож замість цього я створив окрему ієрархію об’єктів, яка реалізує тему. Кожен віджет міститиме посилання на об'єкт, який реалізує операції візуалізації. У багатьох текстах цей клас суфіксований, Implале я відхилився від цієї конвенції про іменування.

Тож тепер моє TextboxWidgetвиглядає так:

TextboxWidget : Widget // text box specific
+ Text
+ MaxLength
+ Font
+ ShowEditor
+ Painter // reference to the implementation of the widget rendering operations
+ Etc

І я можу, щоб мої різні художники успадкували мою базу, що стосується теми, чого я раніше не міг зробити:

Win32WidgetPainter
+ DefaultFont
+ DefaultFontSize
+ DefaultColors
+ DrawFrame
+ Etc

Win32TextboxPainter : Win32WidgetPainter

Win32ListPainter : Win32WidgetPainter

Одне з приємних речей - це те, що я можу динамічно завантажувати реалізації під час виконання, дозволяючи мені додавати стільки тем, скільки мені потрібно, не змінюючи основного програмного забезпечення. Іншими словами, моя "реалізація може змінюватись незалежно від абстракції".


Я не розумію, як це, мабуть, модель моста? Коли ви додаєте новий компонент до ієрархії віджетів, ви змушені додати цей новий Віджет до ВСІХ художників (Win32NewWidgetPainter, PPCNewWidgetPainter). Це НЕ дві незалежно зростаючі ієрархії. Для правильного мостового шаблону ви б не підкласирували клас PlatformWidgetPainter для кожного віджета, а отримали віджет "Дескриптор малювання".
Мазюд

Дякуємо за відгуки, ви праві. Це було років тому, коли я опублікував це, і переглядаючи це зараз, я б сказав, що він добре описує міст до останнього біта, звідки я отримав Win32TextboxPainterі Win32ListPainter звідки Win32WidgetPainter. Ви можете мати дерево спадкування на стороні реалізації, але воно повинно бути більш загальним (можливо StaticStyleControlPainter, EditStyleControlPainterі ButtonStyleControlPainter) з будь-якими необхідними примітивними операціями перевизначені при необхідності. Це ближче до реального коду, на якому я спирався на прикладі.
tcarvin

3

Міст має намір відокремити абстракцію від конкретної реалізації , щоб обидва могли змінюватись незалежно:

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

Міст досягають цього за допомогою складу:

  • абстракція посилається (посилання або вказівник) на об'єкт реалізації
  • абстракція та її вдосконалення відомий лише інтерфейс реалізації

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

Додаткові зауваження щодо частої плутанини

Ця модель дуже схожа на модель адаптера: абстракція пропонує інший інтерфейс для реалізації і використовує композицію для цього. Але:

Ключова відмінність цих моделей полягає в їхніх намірах
- Gamma & al, у " Дизайнерських моделях, елементі програмного забезпечення для багаторазового використання " , 1995

У цій чудовій семінарній книзі про дизайнерські зразки автори також зауважують, що:

  • Адаптери часто використовуються, коли виявляється несумісність і зчеплення непередбачене
  • мости використовуються з початку проектування, коли очікується, що класи розвиватимуться самостійно.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.