Köprü tasarım desenini anlama


24

"Köprü" tasarım modelini hiç anlamıyorum. Çeşitli web sitelerinden geçtim, ancak yardım etmediler.

Bunu anlamamda bana yardımcı olan var mı?


2
Ben de anlamıyorum. Cevapları görmek için sabırsızlanıyorum :)
Violet Giraffe

Tasarım desenlerini anlatan birçok web sitesi ve kitap var. Daha önce yazılmış olanları tekrarlamanın bir değeri olduğunu sanmıyorum, belki belirli bir soru sorabilirsiniz. Farklı kaynaklar ve örnekler arasında geçiş yapmaya devam etmem biraz zaman aldı.
Helena

Yanıtlar:


16

OOP'de polimorfizm kullanıyoruz, böylece bir soyutlama birden fazla uygulamaya sahip olabilir. Aşağıdaki örneğe bakalım:

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

Yeni bir gereksinim getirildi ve trenlerin hızlanma perspektifini getirmesi gerekiyor, bu nedenle kodu aşağıdaki gibi değiştirin.

    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.
        }
    }

Yukarıdaki kod sürdürülemez ve yeniden kullanılabilirlikten yoksundur (aynı palet platformu için hızlandırma mekanizmasını yeniden kullanabileceğimizi varsayarsak). Aşağıdaki kod köprü desenini uygular ve iki farklı soyutlamayı, tren nakliyesini ve ivmesini birbirinden ayırır .

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
Çok güzel bir örnek. İki kuruş ekleyeceğim: bu kalıtım üzerine kompozisyon tercih
etmenin

1
Buna değecekse, bence Monorailgerçekten iki kelime olmadığı için tek bir (bileşik) kelime olması gerektiği gibi olmalı . Bir MonoRail, farklı bir tür demiryolu yerine bir tür Demiryolu alt sınıfı olacaktır. Kullandığımız olmaz Tıpkı SunShineveya CupCakeonlar olurdu SunshineveCupcake
ErikE

Bu “iki farklı soyutlama, tren taşımacılığı ve hızlanma” çizgisi, iki hiyerarşinin ne olduğunu ve çözmeye çalıştığımızın, onları bağımsız olarak değiştirmelerini sağlamak olduğuna yardımcı olur.
wangdq

11

Çoğu tasarım deseninin faydalı isimleri olsa da, “Köprü” ismini ne olduğu konusunda sezgisel olarak görmüyorum.

Kavramsal olarak, bir sınıf hiyerarşisi tarafından kullanılan uygulama ayrıntılarını, genellikle kendi hiyerarşisi ile başka bir nesneye zorlarsınız. Bunu yaparak, bu uygulama detaylarına sıkı bir bağımlılığı ortadan kaldırıyor ve bu uygulamanın detaylarının değişmesine izin veriyorsunuz.

Küçük bir ölçekte, bunu yeni bir davranış biçiminde kullanabileceğiniz şekilde bir strateji modelinin kullanılmasına benziyorum. Ancak, bir stratejiyi sıklıkla bir stratejide görüldüğü gibi sarmak yerine, uygulama nesnesi genellikle daha fazla özellik doludur. Konsepti tüm bir sınıf hiyerarşisine uyguladığınızda, daha büyük desen bir Köprü olur. (Yine, adından nefret ediyorum).

Her gün kullanacağınız bir model değil, ancak çoklu kalıtım için (bariz) bir ihtiyaç duyduğunuzda meydana gelebilecek olası bir sınıf patlamalarını yönetirken yararlı olduğunu gördüm.

İşte gerçek dünyadan bir örnek:

Bir tasarım yüzeyinde kontrolleri bırakmanıza ve yapılandırmanıza izin veren bir RAD aracım var, bu yüzden şöyle bir nesne modelim var:

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

Ve bunun gibi, belki de bir düzine kontrolle.

Ancak daha sonra çoklu temaları desteklemek için yeni bir gereksinim eklendi (look-n-feel). En aşağıdaki temaları var diyelim: Win32, WinCE, WinPPC,WinMo50 , WinMo65. Her tema, DefaultFont, DefaultBackColor, BorderWidth, DrawFrame, DrawScrollThumb, vb. Gibi oluşturma işlemleriyle ilgili işlemler için farklı değerlere veya uygulamalara sahip olacaktır.

Bunun gibi bir nesne modeli oluşturabilirim:

Win32TextboxWidget : TextboxWidget

Win32ListWidget : ListWidget

vb., bir kontrol tipi için

WinCETextboxWidget : TextboxWidget

WinCEListWidget : ListWidget

vb, diğer kontrol tipleri için (tekrar)

Fikri elde edersiniz - temaların # çarpı sayısı olan aletlerin sınıfında bir patlama olur. Bu, RAD tasarımcısını her temanın farkında olarak karmaşık hale getirir. Ayrıca, yeni temalar eklemek RAD tasarımcısını değiştirmeye zorlar. Dahası, bir tema içinde miras almanın harika olacağı çok sayıda ortak uygulama vardır, ancak kontroller zaten ortak bir temelden miras almaktadır (Widget ).

Öyleyse yaptığım şey, temayı uygulayan ayrı bir nesne hiyerarşisi oluşturmak. Her widget, oluşturma işlemlerini uygulayan nesneye referans tutar. Birçok metinde, bu sınıfa bir son eklenmiştir, Implancak ben bu adlandırma kuralından saptım.

Yani şimdi benim TextboxWidgetgörünüşüm şöyle:

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

Ve çeşitli ressamlarımın daha önce yapamadığım temaya özel üslerimi devralmalarını sağlayabilir:

Win32WidgetPainter
+ DefaultFont
+ DefaultFontSize
+ DefaultColors
+ DrawFrame
+ Etc

Win32TextboxPainter : Win32WidgetPainter

Win32ListPainter : Win32WidgetPainter

Güzel şeylerden biri, uygulamaları çalışma zamanında dinamik olarak yükleyebilmem ve çekirdek yazılımı değiştirmeden istediğim kadar tema eklememe izin vermem. Başka bir deyişle, "uygulamam soyutlamadan bağımsız olarak değişebilir".


Bunun nasıl köprü kalıbı olduğunu düşünmüyorum? Widget hiyerarşisine yeni bir bileşen eklediğinizde, bu yeni Widget'ı TÜM Ressamlara (Win32NewWidgetPainter, PPCNewWidgetPainter) eklemek zorunda kalırsınız. Bu iki bağımsız büyüyen hiyerarşi DEĞİLDİR. Uygun bir köprü deseni için, her widget için PlatformWidgetPainter sınıfını alt sınıflara ayırmaz, bunun yerine bir Widget "çizim tanımlayıcısı" almasını istemezsiniz.
Mazyod

Geri bildiriminiz için teşekkürler, haklısınız. Şimdi bu durumda yayınlanmıştır bu yıllar önceydi ve ben de köprü açıklar söyleyebilirim şimdi gözden kadar ben türetilen son bit Win32TextboxPainterve Win32ListPainter gelen Win32WidgetPainter. Sen edebilirsiniz uygulama tarafında bir miras ağacı var, ama (belki daha genel olmalı StaticStyleControlPainter, EditStyleControlPainterve ButtonStyleControlPaintergerektiği gibi geçersiz gerekli tüm ilkel operasyonları ile). Bu, örneğe dayandırdığım gerçek koda daha yakın.
Aralık'ta

3

Köprü bir soyutlamayı somut uygulamasından ayırmayı amaçlamaktadır , böylece her ikisi de bağımsız olarak değişebilir:

  • soyutlamayı alt sınıflandırma ile düzeltin
  • soyutlamayı ve ayrıntılarını bilmek zorunda kalmadan, alt sınıflandırma yoluyla da farklı uygulamalar sağlayın.
  • Gerekirse, en uygun uygulama olan çalışma zamanında seçin .

Köprü kompozisyon kullanarak bunu başarır:

  • soyutlama, bir uygulama nesnesine (başvuru veya işaretçi) başvuruyor
  • soyutlama ve iyileştirmeleri sadece uygulama arayüzünü biliyordu

görüntü tanımını buraya girin

Sık görülen bir karışıklık hakkında ek açıklamalar

Bu model adaptör modeline çok benzer: soyutlama , bir uygulama için farklı bir arayüz sunar ve bunu yapmak için kompozisyon kullanır. Fakat:

Bu modeller arasındaki temel fark, niyetlerinde yatar
- Gamma & al, " Tasarım desenleri, yeniden kullanılabilir OO yazılımının elemanı " , 1995

Tasarım kalıpları üzerine bu mükemmel seminal kitabında, yazarlar şunları da gözlemler:

  • Adaptörler sıklıkla bir uyumsuzluk keşfedildiğinde ve kuplaj öngörülmediğinde kullanılır
  • Köprüler, tasarımın başından itibaren, sınıfların bağımsız olarak gelişmesi beklendiğinde kullanılır.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.