Tasarım kalıpları ve OOP uygulamaları üzerine düşünme, dinamik ve zayıf yazılan dillerde nasıl değişir?


11

Zaten bu çizgiler boyunca oldukça yararlı bir soru var (" OOP Olmayan Tasarım Desenleri? "), Ancak dinamik ve zayıf yazılan dillerle yeni başlayan biri için geçiş bakış açısını merak ediyorum.

Yani: Diyelim ki yıllardır C ++, C # veya Java'da program yapıyorum ve GoF tasarım desenleri, Fowler'in Kurumsal Uygulama Mimarisi Desenleri , SOLID ilkeleri vb. m Ruby, Python, JavaScript, vb. ile ilgileniyorum ve bilgimin nasıl uygulandığını merak ediyorum. Muhtemelen birçok durumda doğrudan çeviri yapabilirim, ancak neredeyse kesinlikle bu yeni ortamımdan tam olarak faydalanmayacaktır. Ördek tek başına yazmak, arayüz tabanlı düşüncelerimin çoğunu kafasına çevirir.

Aynı ne kalır? Hangi değişiklikler? SOLID ya da dinamik bir aceminin bilmesi gereken kanonik kalıplar (belki de tamamen yeni olanlar) gibi yol gösterici ilkeler var mı?

Yanıtlar:


7

Aynı ne kalır? Hangi değişiklikler?

Desenler aynı. Dil teknikleri değişir.

SOLID gibi yol gösterici ilkeler var mı,

Evet. Gerçekten de yol gösterici ilkeler olarak kalırlar. Hiçbirşey değişmez.

ya da dinamik bir dil öğrenenlerin bilmesi gereken kanonik kalıplar (belki de tamamen yeni olanlar)?

Bazı şeyler benzersizdir. Çoğunlukla etkisi uygulama tekniklerinin değişmesidir.

Bir desen - iyi - bir modeldir . Yasa değil. Bir altyordam değil. Makro değil. Tekrarlanan iyi bir fikir çünkü iyi bir fikir.

İyi fikirler modası geçmez veya önemli ölçüde değişmez.

Diğer notlar. Python "zayıf yazılmamış". Java veya C ++ 'dan daha güçlü yazılmıştır, çünkü döküm işlemi yoktur. [Evet, bir nesne ile ilişkili sınıfı geçmenin bir yolu var, ama bu telaşlı, yasal bir noktayı kanıtlamak dışında yapılan bir şey değil.]

Ayrıca. Çoğu tasarım modeli, polimorfizmden yararlanmak için farklı yollara dayanmaktadır.

Bak Devletin veya Command veya Memento örnek olarak. Polimorfik durumlar, komutlar veya durum değişikliklerinin anıları oluşturmak için sınıf hiyerarşileri vardır. Python'da bunu yaptığınızda hiçbir şey önemli ölçüde değişmez. Küçük değişiklikler, kesin sınıf hiyerarşisinin gevşemesini içerir, çünkü Python'daki polimorfizm, ortak atalara değil, ortak yöntemlere bağlıdır.

Ayrıca, bazı paternler geç bağlanmayı sağlama girişimidir. En Fabrika desenleri uygulamada her C ++ modülü derlemeye olmadan bir sınıf hiyerarşisi kolay değişikliğe izin yönelik olduğu belirtildi lı. Bu, dinamik bir dilde ilginç bir optimizasyon değildir. Bununla birlikte, uygulama detaylarını gizlemenin bir yolu olarak bir Fabrika hala büyük bir değere sahiptir.

Bazı desenler derleyici ve bağlayıcıyı sürmek için yapılan bir girişimdir. Örneğin Singleton , kafa karıştırıcı küreseller yaratmak için var, ancak en azından onları kapsıyor. Python singleton sınıfları hoş bir olasılık değil. Ancak Python modülleri zaten tek tonludur, bu yüzden çoğumuz sadece bir modül kullanırız ve bir Singleton sınıfıyla uğraşmaktan kaçınırız .


SOLID ile "hiçbir şeyin değişmediğini" söylemezdim. Dile ve nesne modeline bağlı olarak, Açık-Kapalı Prensibi ve Liskov İkame Prensibi anlamsız olabilir. (JavaScript ve Go her ikisi de akla geliyor.)
Mason Wheeler

@Mason Wheeler. Açık-Kapalı benim deneyimimde dilden bağımsızdır. Açık veya kapalı tasarımın JavaScript veya Go ile nasıl "anlamsız" olduğuna dair daha somut örnekler sunmanız gerekir. Liskov ikamesi, belki de JavaScript için geçerli değildir, ancak temel desen - polimorfizm hala geçerli görünmektedir.
S.Lott

@ S.Lott: Düzenlemede güzel güncellemeler; orijinal cevaptan çok daha ilginçti: P. Python hatamı düzelttiğiniz için teşekkürler. Genel olarak spesifik örüntü örnekleri ve dinamik dillere, polimorfizme, geç bağlamaya vb.
Domenic

@ S.Lott: Çünkü Açık / Kapalı, bu dillerin sahip olmadığı kalıtımla ilgilidir. (Ayrıca, bir nesnenin "modifikasyon için kapalı" olduğu fikri, Ruby kodlayıcılarının çoğunda iyi oturmayacaktır ...)
Mason Wheeler

@Manon Wheeler: Açık / Kapalı konularına ilişkin açıklama için teşekkürler. JavaScript istisnasının önemli olduğunu düşünüyorum, ancak soru çok açık olduğu için (JavaScript, Python ve Ruby'nin yanı sıra ETC adı verilen bir dil listeleniyor) Özel durumun nasıl ele alınacağından emin değilim.
S.Lott

8

Peter Norvig 1998'de bu soruyu ele aldı, fark ettiği bir dizi ayrıntılı şey için http://norvig.com/design-patterns/ppframe.htm ve http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeatures için konu hakkında daha fazla tartışma.

Kısa sürüm, dilinizde daha fazla özellik olduğunda, tekrarlayan tasarım modellerinin genellikle görünmez olma noktasına kadar daha basit olma eğilimindedir. Bunun, GoF'un tanımladığı tasarım modellerinin çoğu için geçerli olduğunu buldu.


8

Dinamik bir nesne yönelimli dilde programlama, aynı kalıp ve ilkelerin çoğunu kullanır, ancak çevre nedeniyle bazı ince ayarlar ve farklılıklar vardır:

Arabirimleri Ördek Yazma ile Değiştirin - Dörtlü Çete, saf sanal işlevlere sahip soyut bir temel sınıf kullanmanızı söyleyeceği ve Java'da, dinamik bir dilde bir arabirim kullandığınızda, yalnızca bir anlayışa ihtiyacınız vardır. Herhangi bir nesneyi herhangi bir yerde kullanabileceğiniz ve gerçekten çağrılan yöntemleri uygularsa iyi çalışacağından, resmi bir arayüz tanımlamanız gerekmez. Birini belgelemeye değer olabilir , böylece gerçekten neyin gerekli olduğu açıktır.

İşlevler Çok Nesnelerdir - Kararın eylemden ayrılmasıyla ilgili birçok örüntü vardır; Komuta, Strateji, birinci sınıf fonksiyonları ile bir dilde vb Sorumluluk, zinciri, sadece nesneleri yapma etrafında yerine bir işlev geçmek sıklıkla makul .doIt()yöntemlerle. Bu modeller "daha yüksek dereceli bir fonksiyon kullan" a dönüşür.

SATILDI - Arayüz Ayırma Prensibi, arayüz olmaması nedeniyle burada en büyük darbeyi alır. Yine de prensibi göz önünde bulundurmalısınız, ancak kodunuzda yeniden aktaramazsınız. Sizi burada sadece kişisel uyanıklık koruyacaktır. Yukarı tarafta, bu prensibi ihlal etmenin neden olduğu acı, ortak dinamik ortamlarda çok azalır.

“... kendi özelliğimle ... Deyim!” - Her dilin iyi uygulamaları ve kötü uygulamaları vardır ve bu dillerde en iyi kodu istiyorsanız bunları öğrenmeniz ve takip etmeniz gerekir. Mükemmel bir şekilde yazılmış yineleyici modeli, örneğin yerleşik liste kavramalarına sahip bir dilde çıkarılabilir.


3

Deneyimlerime göre, bazı Desenler Python'da hala yararlıdır ve kurulumu daha statik dillerden daha kolaydır. Bazı OTON Desenleri, Singleton Paterni gibi gerekli değildir, hatta kaşlarını çatmaz. Bunun yerine modül düzeyinde bir değişken veya işlev kullanın. Veya Borg Desenini kullanın.

Bir Yaratılış Deseni ayarlamak yerine, genellikle nesnelerin yaratıldığı bir çağrıyı geçirmek yeterlidir. Bu bir işlev, __call__yöntemli bir nesne veya hatta bir sınıf olabilir, çünkü new()Python'da sadece sınıfın bir çağrılması yoktur :

def make_da_thing(maker, other, stuff):
    da_thing = maker(other + 1, stuff + 2)
    # ... do sth
    return da_thing

def maker_func(x, y):
     return x * y

class MakerClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
...
a = make_da_thing(maker_func, 5, 8)
b = make_da_thing(MakerClass, 6, 7)

Durum ve Strateji Paterni, C ++ ve Java gibi dillerde çok benzer bir yapıyı paylaşır. Python'da daha az. Strateji Kalıbı aşağı yukarı aynı kalır, ancak Devlet Kalıbı çoğunlukla gereksiz hale gelir. Statik dillerdeki Durum Düzeni, çalışma zamanında sınıf değişikliğini simüle eder. Python'da şunları yapabilirsiniz: çalışma zamanında bir nesnenin sınıfını değiştirme. Kontrollü, kapsüllenmiş bir şekilde yaptığınız sürece, iyi olmalısınız:

class On(object):
    is_on = True
    def switch(self):
        self.__class__ = Off

class Off(object):
    is_on = False
    def switch(self):
        self.__class__ = On
...

my_switch = On()
assert my_switch.is_on
my_switch.switch()
assert not my_switch.is_on

Statik Tip Sevk'ye dayanan desenler çalışmaz veya farklı çalışır. Çok fazla kazan plakası kodu yazmak zorunda değilsiniz, örneğin Ziyaretçi Deseni: Java ve C ++ 'da her ziyaret edilebilir sınıfta bir kabul yöntemi yazmanız gerekirken, Python'da bu işlevselliği Visitable gibi bir mixin sınıfı aracılığıyla devralabilirsiniz.

class Visitable(object):
    def accept(self, visitor):
        visit = getattr(visitor, 'visit' + self.__class__.__name__)
        return visit(self)
...

class On(Visitable):
    ''' exactly like above '''

class Off(Visitable):
    ''' exactly like above '''

class SwitchStatePrinter(object): # Visitor
    def visitOn(self, switch):
         print 'the switch is on'
    def visitOff(self, switch):
         print 'the switch is off'

class SwitchAllOff(object): # Visitor
    def visitOn(self, switch):
         switch.switch()
    def visitOff(self, switch):
         pass
...
print_state = SwitchStatePrinter()
turn_em_off = SwitchAllOff()
for each in my_switches:
    each.accept(print_state)
    each.accept(turn_em_off)

Bir Desenin Statik Dilde uygulanmasını gerektiren birçok durum Python'da böyle bir şey yapmaz. Birçok şey, daha üst düzey işlevler (dekoratörler, işlev fabrikaları) veya meta sınıfları gibi diğer tekniklerle çözülebilir.


Şimdi cevabınızın cevabının sadece sorduğum soruyu kapsadığını anlıyorum: Python'da bir fabrika uygulamak için üzerine yazmak__class__ iyi bir fikir mi?
rds
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.