Dekoratör tasarım desen hakkında yeni soru


18

Bir programlama makalesi okuyordum ve Dekoratör modelinden bahsetti. Bir süredir program yapıyorum ama herhangi bir örgün eğitim ya da eğitim almadım, ama standart kalıpları ve benzerlerini öğrenmeye çalışıyorum.

Dekoratöre baktım ve üzerinde bir Wikipedia makalesi buldum . Şimdi Dekoratör deseni kavramını anlıyorum, ancak bu pasajla biraz karıştım:

Örnek olarak, bir pencere sistemindeki bir pencereyi düşünün. Pencere içeriğinin kaydırılmasına izin vermek için, uygun şekilde yatay veya dikey kaydırma çubukları eklemek isteyebiliriz. Pencerelerin Window sınıfının örnekleri ile temsil edildiğini ve bu sınıfın kaydırma çubuğu eklemek için işlevselliği olmadığını varsayalım. Bunları sağlayan bir alt sınıf ScrollingWindow oluşturabiliriz veya bu işlevi mevcut Window nesnelerine ekleyen bir ScrollingWindowDecorator oluşturabiliriz. Bu noktada, her iki çözüm de iyi olur.

Şimdi, pencerelerimize kenarlık ekleme yeteneğini de istediğimizi varsayalım. Yine, orijinal Window sınıfımızın desteği yok. ScrollingWindow alt sınıfı artık yeni bir tür pencere oluşturduğundan bir sorun oluşturmaktadır. Tüm pencerelere sınır desteği eklemek istiyorsak WindowWithBorder ve ScrollingWindowWithBorder alt sınıflarını oluşturmalıyız. Açıkçası, bu sorun eklenecek her yeni özellikle kötüleşiyor. Dekoratör çözümü için basitçe yeni bir BorderedWindowDecorator oluşturuyoruz - çalışma zamanında mevcut pencereleri, uygun gördüğümüz gibi ScrollingWindowDecorator veya BorderedWindowDecorator veya her ikisiyle de dekore edebiliriz.

Tamam, tüm pencerelere kenarlık eklemeyi söylediklerinde, neden seçeneğe izin vermek için orijinal Window sınıfına işlevsellik eklemiyorsunuz? Gördüğüm gibi, alt sınıflandırma sadece bir sınıfa belirli işlevler eklemek veya bir sınıf yöntemini geçersiz kılmak içindir. Mevcut tüm nesnelere işlevsellik eklemem gerekirse, neden bunu yapmak için üst sınıfı değiştirmiyorum?

Makalede başka bir satır daha vardı:

Dekoratör deseni, alt sınıflamaya bir alternatiftir. Alt sınıflandırma derleme zamanında davranış ekler ve değişiklik orijinal sınıfın tüm örneklerini etkiler; dekorasyon tek tek nesneler için çalışma zamanında yeni davranışlar sağlayabilir.

"... Değişiklik orijinal sınıfın tüm örneklerini etkiler" dedikleri yere ulaşamıyorum - alt sınıflama ana sınıfı nasıl değiştirir? Alt sınıflamanın bütün mesele bu değil mi?

Makalenin, birçok Wiki gibi, açıkça yazılmadığını varsayacağım. Dekoratörün bu son satırdaki yararlılığını görebiliyorum - "... tek tek nesneler için çalışma zamanında yeni davranışlar sağlayın."

Bu kalıbı okumadan, tek tek nesneler için çalışma zamanında davranışı değiştirmem gerekirse, muhtemelen söz konusu davranışı etkinleştirmek / devre dışı bırakmak için üst veya alt sınıfa bazı yöntemler inşa ederdim. Lütfen Dekoratörün faydasını gerçekten anlamama yardımcı olun ve yeni başlayan düşüncem neden kusurlu?


düzenlemeyi takdir ediyorum, Walter ... fyi, "erkekleri" kadınları dışlamak için değil, gayri resmi bir selam olarak kullandım.
Jim

Düzenleme sadece genel olarak selamlamayı kaldırmak olacaktır. Sorularda birini kullanmak standart SO / SE protokolü değildir [endişelenmeyin, doğrudan soruya atlamanın kaba olduğunu düşünmüyoruz]
Farrell

havalı, teşekkürler! o sadece "cinsiyet kaldırma" olarak etiketlendi ve ben kadın düşmanı ya da bir şey olduğumu düşünmekten nefret ediyorum !! :)
Jim

Onları "hizmetler" olarak adlandırılan yasal işlemlerden kaçınmak için çok kullanıyorum: medium.com/@wrong.about/…
Zapadlo

Yanıtlar:


13

Dekoratör kalıbı, miras üzerine kompozisyonu tercih eden modeldir [öğrenmesi yararlı başka bir OOP paradigması]

Dekoratör modelinin ana faydası alt sınıflamaya göre daha fazla karıştırma ve eşleme seçeneği sağlamaktır. Örneğin, bir pencerenin sahip olabileceği 10 farklı davranışınız varsa, bu - alt sınıflama ile - kaçınılmaz olarak çok fazla kod yeniden kullanımını içerecek olan her farklı kombinasyonu oluşturmanız gerektiği anlamına gelir.
Ancak, yeni bir davranış eklemeye karar verdiğinizde ne olur?

Dekoratör ile, sadece bu davranışı tanımlayan yeni bir sınıf eklersiniz ve bu kadar - desen, kodun geri kalanında herhangi bir değişiklik yapmadan bunu etkili bir şekilde bırakmanıza izin verir.
Alt sınıflama ile ellerinizde bir kabus var.
Sorduğunuz bir soru, "alt sınıflandırma ana sınıfı nasıl değiştirir?" Üst sınıfı değiştirdiği anlamına gelmez; bir örnek söylediğinde, 'Java veya C # kullanıyorsanız, örneğin newkomutu kullanarak' örneklediğiniz 'herhangi bir nesne anlamına gelir . Sözü edilen şey, bu değişiklikleri bir sınıfa eklediğinizde, aslında ihtiyacınız olmasa bile, bu değişikliğin orada olması için başka seçeneğiniz yoktur.

Alternatif olarak, tüm işlevlerini bayraklar aracılığıyla açıp kapatarak tek bir sınıfa koyabilirsiniz ... ancak bu, projeniz büyüdükçe daha büyük ve daha büyük hale gelen tek bir sınıfla sonuçlanır.
Projenizi bu şekilde başlatmak olağandışı değil ve etkili bir kritik kütleye çarptığınızda bir dekoratör desenine yeniden bakın.

Dikkat edilmesi gereken ilginç bir nokta: aynı işlevi birden çok kez ekleyebilirsiniz; örneğin, istediğiniz gibi çift, üçlü veya istediğiniz miktarda veya kenarlıklı bir pencereniz olabilir.

Desenin ana noktası, çalışma zamanı değişikliklerini etkinleştirmektir: program çalışana kadar pencerenin nasıl görünmesini istediğinizi bilmiyor olabilirsiniz ve bu da onu kolayca değiştirmenize izin verir. Kabul edilirse, bu alt sınıflandırma yoluyla yapılabilir, ancak bu kadar güzel olamaz.
Son olarak, düzenleyemeyeceğiniz sınıflara işlevin eklenmesine izin verir - örneğin mühürlü / final sınıflarında veya diğer API'lardan sağlananlar


2
Teşekkürler Farrell - "Alternatif olarak, tüm işlevlerini bayraklar aracılığıyla açıp kapatarak tek bir sınıfa koyabilirsiniz ... ama bu, projeniz büyüdükçe daha büyük ve daha büyük hale gelen tek bir sınıfla sonuçlanır." bu benim için tıkladı. Sanırım sorunun bir parçası, dekoratörün bana mantıklı geldiği kadar büyük bir sınıfta hiç çalışmadım. Büyük düşünerek, kesinlikle faydalarını görebiliyorum ... teşekkürler!
Jim

Ayrıca, mühürlü sınıflarla ilgili bölüm çok mantıklı ... teşekkürler!
Jim

3

Alt sınıflandırma ile kaydırma çubukları ve kenarlıklar ekleme olanaklarını göz önünde bulundurun. Her olasılığı istiyorsanız, dört sınıf (Python) alırsınız:

class Window(object):
    def draw(self):
        "do actual drawing of window"

class WindowWithScrollBar(Window):
    def draw(self):
        Window.draw(self)
        "do actual drawing of scrollbar"

class WindowWithBorder(Window):
    def draw(self):
        Window.draw(self)
        "do actual drawing of border"

class WindowWithScrollBarAndBorder(Window):
    def draw(self):
        WindowWithScrollBar.draw(self)
        WindowWithBorder.draw(self)

Şimdi, WindowWithScrollBarAndBorder.draw()pencere iki kez çizilir ve ikinci kez uygulamaya bağlı olarak, önceden çizilmiş Kaydırma Çubuğunun üzerine yazabilir veya yazamaz. Yani türetilmiş kodunuz başka bir sınıfın uygulanmasına sıkı sıkıya bağlıdır ve Windowsınıf davranışını her değiştirdiğinizde bununla ilgilenmeniz gerekir . Bir çözüm, türetilmiş sınıfların süper sınıflarından kodu kopyalayıp yapıştırmak ve türetilmiş sınıfların gereksinimlerine göre ayarlamak olacaktır, ancak bir süper sınıftaki her değişiklik tekrar kopyala yapıştırılmalı ve tekrar ayarlanmalıdır, böylece tekrar türetilmiş sınıflar temel sınıfa sıkıca bağlanır (kopyala-yapıştır ayarı ile). Başka bir sorun, bir pencerenin sahip olabileceği veya olmayabileceği başka bir özelliğe ihtiyacınız varsa, her sınıfı iki katına çıkarmanız gerekir:

class Window(object):
    ...

class WindowWithGimmick(Window):
    ...

class WindowWithScrollBar(Window):
    ...

class WindowWithBorder(Window):
    ...

class WindowWithScrollBarAndBorder(Window):
    ...

class WindowWithScrollBarAndGimmick(Window):
    ...

class WindowWithBorderAndGimmick(Window):
    ...

class WindowWithScrollBarAndBorderAndGimmick(Window):
    ...

Bu, f ile karşılıklı bağımsız özellikler kümesi için f anlamına gelir. özellik sayısı olarak, 2 ** | f | sınıflar, ör. 10 özelliğiniz varsa 1024 sıkı sıkıya bağlı sınıf elde edersiniz. Dekoratör Desenini kullanırsanız, her özellik kendi bağımsız ve gevşek bağlı sınıfına sahip olur ve sadece 1 + | f | (yukarıdaki örnek için 11'dir).


Düşünüyorum, sınıfları eklemeye devam etmek değil - orijinal (alt) sınıfa işlevsellik eklemek olurdu. yani Window (nesne) sınıfında: scrollBar = true, border = false, vb ... 1!
Jim

iyi, bunu yapmak için temsilcisi var +1!
Jim

2

Ben bu özel desen üzerinde bir uzman değilim, ama gördüğüm gibi Dekoratör desen değiştirme veya alt sınıf yeteneğine sahip olmayabilir sınıflara uygulanabilir (kodunuz olmayabilir ve örneğin mühürlenmiş olabilir) ). Örneğinizde, Window sınıfını yazmadıysanız ancak sadece tüketiyorsanız ne olur? Window sınıfı bir arabirime sahip olduğu ve bu arabirime karşı programladığınız sürece Decorator'ınız aynı arabirimi kullanabilir, ancak işlevselliği genişletebilir.

Bahsettiğiniz örnek aslında burada oldukça düzgün bir şekilde ele alınmıştır:

Bir nesnenin işlevselliğini genişletme, kalıtım kullanılarak statik olarak (derleme zamanında) yapılabilir, ancak bir nesne kullanıldıkça bir nesnenin işlevselliğini dinamik olarak (çalışma zamanında) genişletmek gerekebilir.

Grafik pencerenin tipik örneğini düşünün. Grafik penceresinin işlevselliğini genişletmek için, örneğin pencereye bir çerçeve ekleyerek, FramedWindow sınıfı oluşturmak için pencere sınıfının genişletilmesi gerekir. Çerçeveli bir pencere oluşturmak için FramedWindow sınıfının bir nesnesini oluşturmak gerekir. Bununla birlikte, düz bir pencereyle başlamak ve çerçeveli bir pencere haline gelmek için çalışma zamanında işlevselliğini genişletmek imkansız olacaktır.

http://www.oodesign.com/decorator-pattern.html

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.