"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ı?
"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ı?
Yanıtlar:
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*/}
Monorail
gerç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ı SunShine
veya CupCake
onlar olurdu Sunshine
veCupcake
Ç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, Impl
ancak ben bu adlandırma kuralından saptım.
Yani şimdi benim TextboxWidget
gö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".
Win32TextboxPainter
ve Win32ListPainter
gelen Win32WidgetPainter
. Sen edebilirsiniz uygulama tarafında bir miras ağacı var, ama (belki daha genel olmalı StaticStyleControlPainter
, EditStyleControlPainter
ve ButtonStyleControlPainter
gerektiği gibi geçersiz gerekli tüm ilkel operasyonları ile). Bu, örneğe dayandırdığım gerçek koda daha yakın.
Köprü bir soyutlamayı somut uygulamasından ayırmayı amaçlamaktadır , böylece her ikisi de bağımsız olarak değişebilir:
Köprü kompozisyon kullanarak bunu başarır:
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: