Yalnızca yapıcı alt sınıflar: Bu bir kalıp karşıtı mı?


37

Bir iş arkadaşınızla bir tartışma yapıyordum ve alt sınıflamanın amacı hakkında çelişkili sezgiler yaşadık. Sezgim, eğer bir alt sınıfın birincil işlevi, üst öğesinin sınırlı bir değer değer aralığını ifade etmesiyse, o zaman muhtemelen bir alt sınıf olmamalıdır. Ters sezgi için savundu: alt sınıflamanın bir nesnenin daha "spesifik" olduğunu gösterir ve bu nedenle bir alt sınıf ilişkisi daha uygundur.

Sezgilerimi daha somut bir şekilde ifade etmek gerekirse, bir üst sınıfı genişleten bir alt sınıfa sahipsem ancak alt sınıfı geçersiz kılan tek kodun bir kurucu olduğunu düşünüyorum (evet, kurucuların genellikle "geçersiz kılma" etmediğini, o zaman benimle) gerçekte ihtiyaç duyulan şey yardımcı bir yöntemdi.

Örneğin, bu biraz gerçek hayat sınıfını düşünün:

public class DataHelperBuilder
{
    public string DatabaseEngine { get; set; }
    public string ConnectionString { get; set; }

    public DataHelperBuilder(string databaseEngine, string connectionString)
    {
        DatabaseEngine = databaseEngine;
        ConnectionString = connectionString;
    }

    // Other optional "DataHelper" configuration settings omitted

    public DataHelper CreateDataHelper()
    {
        Type dataHelperType = DatabaseEngineTypeHelper.GetType(DatabaseEngine);
        DataHelper dh = (DataHelper)Activator.CreateInstance(dataHelperType);
        dh.SetConnectionString(ConnectionString);

        // Omitted some code that applies decorators to the returned object
        // based on omitted configuration settings

        return dh;
    }
}

Onun iddiası şunun gibi bir alt sınıfa sahip olmanın tamamen uygun olacağını söyledi:

public class SystemDataHelperBuilder
{
    public SystemDataHelperBuilder()
        : base(Configuration.GetSystemDatabaseEngine(),
               Configuration.GetSystemConnectionString())
    {
    }
 }

Öyleyse, soru:

  1. Tasarım kalıplarından bahseden insanlar arasında bu sezgilerden hangisi doğrudur? Alt sınıflama yukarıda açıklandığı gibi bir anti-patern midir?
  2. Bir anti-patern ise, adı nedir?

Kolayca googleable bir cevap olduğu ortaya çıkarsa özür dilerim; google’da yaptığım aramalar çoğunlukla aradıklarım değil teleskop kurucu anti-patern hakkında bilgi verdi.


2
Bir isimdeki "Helper" kelimesini bir antipattern olarak kabul ediyorum. Bir şeye ve bir şeye sürekli referanslar içeren bir makale okumak gibi. Ne söyle olduğunu . Fabrika mu Yapıcı? Bana göre tembel bir düşünce sürecine değiniyor ve uygun bir semantik isim onu ​​yönlendireceği için tek sorumluluk ilkesinin ihlalini teşvik ediyor. Diğer seçmenlerle aynı fikirdeyim ve @ lxrec'in cevabını kabul etmelisiniz. Bir fabrika yöntemi için bir alt sınıf oluşturmak, kullanıcıların belgelerde belirtilen doğru argümanları iletmelerine güvenemediğiniz sürece, tamamen anlamsızdır. Bu durumda yeni kullanıcılar edinin.
Aaron Hall

@ Ixrec'in cevabına kesinlikle katılıyorum. Ne de olsa, cevabı her zaman haklı olduğumu ve iş arkadaşımın yanlış olduğunu söylüyor. ;-) Ama cidden, işte bu yüzden onu kabul etmekten garip hissettim; Önyargı ile suçlanabileceğimi düşündüm. Ancak programcıların StackExchange'lerinde yeniyim; Görgü kurallarının ihlali olmayacağından emin olsaydım kabul etmeye istekli olurdum.
az,

1
Hayır, en değerli olduğunu düşündüğünüz cevabı kabul etmeniz bekleniyor. Topluluğun şimdiye kadar en değerli olduğunu düşündüğü kişi Ixrec'in 3'ten 1'e kadar olanlarıdır. Bu nedenle sizden kabul etmenizi beklerler. Bu toplulukta, yanlış cevap kabul eden bir sorgulayıcıda ifade edilen çok az hayal kırıklığı var, ancak soruları cevaplayan ve asla cevap vermeyen çok fazla hayal kırıklığı var. Kimse bunun yerine görünen oylama, şikayet, burada kabul cevap şikayetçi olduğunu Not kendini düzeltilmesi gereken: stackoverflow.com/q/2052390/541136
Aaron Hall

Çok iyi, kabul edeceğim. Beni burada topluluk standartları hakkında eğitmeye zaman ayırdığınız için teşekkür ederiz.
HardlyKnowEm

Yanıtlar:


54

Tek yapmak istediğiniz, belirli argümanlarla X sınıfı oluşturmaksa, alt sınıflama bu amacı ifade etmenin tuhaf bir yoludur, çünkü sınıfların ve mirasın size sunduğu özelliklerin hiçbirini kullanmıyorsunuzdur. Gerçekten bir anti-patern değil, sadece garip ve biraz anlamsız (bunun için başka nedenleriniz yoksa). Bu amacı dile getirmenin daha doğal bir yolu, "yardımcı yönteminiz" için süslü bir isim olan bir Fabrika Yöntemi olacaktır .

Genel sezgiyle ilgili olarak, hem "daha spesifik" hem de "sınırlı bir aralık", alt sınıflar hakkında düşünmek için potansiyel olarak zararlı düşünme yollarıdır, çünkü her ikisi de Kare'yi Dikdörtgen'in bir alt sınıfını yapmanın iyi bir fikir olduğunu ima eder. LSP gibi resmi bir şeye güvenmeden, daha iyi bir sezginin, bir alt sınıfın ya temel arayüzün bir uygulamasını sağladığını ya da yeni işlevsellik eklemek için arayüzü genişlettiğini söyleyebilirim .


2
Fabrika Yöntemleri olsa da, kod tabanınızdaki belirli davranışları (argümanlara tabi) uygulamanıza izin vermeyin. Ve bazen, bu sınıf / yöntem / alanın SystemDataHelperBuilderözel olarak aldığını açıkça belirtmek yararlı olur .
Telastyn

3
Ah, kare ve dikdörtgen argümanı tam olarak aradığım şeydi sanırım. Teşekkürler!
HardlyKnowEm

7
Tabii ki, karenin dikdörtgenin bir alt sınıfı olması, değişmezlerse tamam olabilir. Gerçekten LSP'ye bakmalısın.
David Conrad

10
Kare / dikdörtgen "problem" ile ilgili olan, geometrik şekillerin değişmez olmasıdır. Her zaman bir dikdörtgenin anlamlı olduğu bir kare kullanabilirsiniz, ancak yeniden boyutlandırma kareler veya dikdörtgenlerin yapacağı bir şey değildir.
Doval

3
@nha LSP = Liskov Değişim Prensibi
Ixrec 27:15

16

Bu sezgilerden hangisi doğrudur?

İş arkadaşınız doğru (standart tip sistemler varsayarsak).

Bir düşünün, sınıflar olası yasal değerleri temsil eder. Sınıfın Abir bayt alanı varsa F, bunun A256 yasal değere sahip olduğunu düşünmeye meyilli olabilirsiniz , ancak bu sezgi yanlış. A"her zaman değerlerin her geçirgenliğini" ile "kısıtlayan alan F" 0-255 olmalıdır ".

Başka bir bayt alanına Asahip Bolanı genişletirseniz FF, bu kısıtlama ekliyor . " FBayt olan değer" yerine " Fbayt FFolan ve aynı zamanda bayt olan" değerine de sahipsiniz . Eski kuralları koruduğunuzdan, bassetype için çalışan her şey hala alt türünüz için çalışır. Ancak kurallar eklediğiniz için, "her şey olabilir" den uzağa uzmanlaşıyorsunuz.

Ya da başka bir şekilde düşünmenin, varsayalım A: alt tipleri bir grup vardı B, Cve D. Bir tür değişkeni Abu alt türlerden herhangi biri olabilir, ancak bir tür değişkeni Bdaha belirgindir. (Çoğu tip sistemde) a Cveya a olamaz D.

Bu bir anti-kalıp mı?

Enh? Özel nesnelere sahip olmak kullanışlıdır ve yasalara açıkça zarar vermez. Alt sonucu kullanarak bu sonucun elde edilmesi belki biraz sorgulanabilir, ancak elinizde bulunan araçlara bağlıdır. Daha iyi araçlarla bile, bu uygulama basit, anlaşılır ve sağlamdır.

Bunu bir anti-patern olarak düşünmemeliyim çünkü hiçbir durumda açıkça yanlış ve kötü değil.


5
"Daha fazla kural, daha az olası değer anlamına gelir, daha belirgindir." Bunu gerçekten takip etmiyorum. Tip byte and bytekesinlikle sadece tipten daha fazla değere sahiptir byte; 256 kat daha fazla. Bu bir yana, kuralları bir dizi unsurla (veya kesin olmak istiyorsanız kardinalite) sınırlandırabileceğinizi sanmıyorum. Sonsuz kümeleri düşündüğünüzde bozuluyor. Tam sayılar olduğu kadar çok sayıda sayı vardır, ancak bir sayının bile hala bir kısıtlama olduğunu bilmek / bana sadece bir tam sayı olduğunu bilmekten daha fazla bilgi verir! Doğal sayılar için de aynı şey söylenebilir.
Doval

6
@Telastyn Konu dışıyız, ancak hatta tamsayılar kümesinin kardinalliğinin (gevşek, "boyut") tüm tamsayılar kümesiyle, hatta tüm rasyonel sayılarla aynı olduğu kanıtlanabilir. Gerçekten harika şeyler. Bkz math.grinnell.edu/~miletijo/museum/infinite.html
HardlyKnowEm

2
Küme teorisi oldukça sezgisel değil. Tamsayıları ve evens'i bire bir yazışmalara koyabilirsiniz (örneğin, işlevi kullanarak n -> 2n). Bu her zaman mümkün değildir; tamsayıları gerçeklerle eşleyemezsiniz, bu yüzden gerçekler kümesi tamsayılardan "daha büyüktür". Ancak, (gerçek) aralığını [0, 1] tüm gerçekler grubuyla eşleştirebilirsiniz, böylece bu onları aynı "boyutta" yapar. Alt kümeler , "her öğenin Ade bir öğesidir B" olarak tanımlanır, çünkü kümeleriniz sonsuz olduğunda, aynı kardinalite oldukları ancak farklı öğelere sahip oldukları olabilir.
Doval

1
Eldeki konuya daha fazla ilişkin olarak, verdiğiniz örnek, nesne yönelimli programlama açısından aslında işlevselliği ek bir alan açısından genişleten bir kısıtlamadır. Çember elips problemi gibi işlevselliği genişletmeyen alt sınıflardan bahsediyorum.
HardlyKnowEm

1
@Doval: "Daha az" anlamına gelebilecek birden fazla anlam var - yani setler üzerinde birden fazla sipariş ilişkisi var. "Bir alt küme" ilişkisi, kümelerde iyi tanımlanmış (kısmi) bir sıralama sağlar. Dahası, "kümenin tüm öğelerinin (belirli bir kümeden) bir üstkümenin daha fazla (yani bir üst kümenin)" yerine getirilmesi "anlamına" daha fazla kural "alınabilir. Bu tanımlarla "daha fazla kural" aslında "daha az değer" anlamına gelir. Bu, kabaca konuşursak, bazı semantik bilgisayar programları modelleri, örneğin Scott alanları gibi yaklaşımdır.
psmears

12

Hayır, bu bir anti-patern değil. Bunun için birkaç pratik kullanım durumu düşünebilirim:

  1. Derleme zamanı kullanmak istiyorsanız, nesne koleksiyonlarının yalnızca belirli bir alt sınıfa uygun olduğundan emin olmak için kontrol edin. Örneğin, sisteminizde varsa MySQLDaove SqliteDaobazı nedenlerden dolayı, bir koleksiyonun yalnızca bir kaynaktan veri içerdiğinden emin olmak istiyorsanız, açıkladığınız gibi alt sınıflar kullanıyorsanız, derleyicinin bu özel doğruluğu doğrulamasını sağlayabilirsiniz. Diğer yandan, veri kaynağını bir alan olarak saklarsanız, bu bir çalışma zamanı kontrolü olur.
  2. Benim şu anki uygulama arasındaki tek ilişki için bir birine sahiptir AlgorithmConfiguration+ ProductClassve AlgorithmInstance. Yapılandırmak Diğer bir deyişle, FooAlgorithmiçin ProductClassözellikler dosyasında, sadece bir tane alabilirsiniz FooAlgorithmo ürün sınıfı için. Verilen için iki FooAlgorithms elde etmenin tek yolu ProductClassbir alt sınıf oluşturmaktır FooBarAlgorithm. Bu tamam, çünkü özellikler dosyasının kullanımını kolaylaştırır (özellikler dosyasındaki bir bölümde birçok farklı yapılandırma için sözdizimine gerek yoktur) ve verilen bir ürün sınıfı için birden fazla örnek olması çok nadirdir.
  3. @ Telastyn'ın cevabı başka iyi bir örnek veriyor.

Alt satır: Bunu yapmanın bir zararı yok. Bir Anti-pattern şöyle tanımlanır:

Bir anti-patern (veya antipattern), genellikle etkisiz olan ve oldukça fazla üretkenlik riski taşıyan tekrarlayan bir soruna ortak bir cevaptır .

Burada son derece üretken olma riski yoktur, bu nedenle bir anti-patern değildir.


2
Evet, soruyu tekrar ifade etmem gerekseydi, "kod kokusu" derdim. Bunu önlemek için, genç geliştiricilerin yeni nesil uyarı gerektirecek yeterince kötü değil, ama bunu görmek, eğer o en şey olabilir kapsayıcı tasarım hatası olduğunu gösteriyor, ancak aynı zamanda sonuçta doğru olabilir.
HardlyKnowEm

Nokta 1, hedefte haklı. 2. noktayı gerçekten anlamadım, ama eminim ki bu kadar iyi ... :)
Phil

9

Şey bir desen veya bir antipattern neyi dil ve çevre sizin yazmakta olduğunuz önemli ölçüde bağlıdır edin. Örneğin, fordöngüler bir desen olan montaj, C ve benzeri dillerde ve lisp bir antipattern.

Size uzun zaman önce yazdığım bazı kodların hikayesini anlatayım ...

LPC adlı bir dildeydi ve oyunda büyü yapmak için bir çerçeve oluşturdu. Bazı kontrolleri ele alan bir savaş büyücülerinin alt sınıfına sahip bir büyü süper sınıfına ve sonra tek hedef doğrudan hasar büyülerine yönelik bir alt sınıfa sahiptiniz, daha sonra bireysel büyülere sınıflanan - sihirli füze, yıldırım cıvatası ve benzeri.

LPC'nin çalışma şeklinin doğası, Singleton olan bir ana nesneye sahip olmanızdı. gitmeden önce 'eww Singleton' - öyleydi ve hiç "eww" değildi. Biri büyülerin kopyasını çıkarmamış, daha çok büyülerdeki (etkili) statik yöntemleri başlatmış. Sihirli füzenin kodu şöyle gözüküyordu:

inherit "spells/direct";

void init() {
  ::init();
  damage = 10;
  cost = 3;
  delay = 1.0;
  caster_message = "You cast a magic missile at ${target}";
  target_message = "You are hit with a magic missile cast by ${caster}";
}

Ve bunu görüyor musun? Bir kurucu sadece sınıf. Üst soyut sınıfında bulunan bazı değerleri belirledi (hayır, belirleyici kullanmamalı - değişmez) ve öyleydi. İşe yaradı sağ . Kodlaması kolay, genişletilmesi ve anlaşılması kolaydı.

Bu tür bir kalıp, soyut bir sınıfı genişleten ve kendi başına bir kaç değer ayarlayan bir alt sınıfın olduğu diğer durumlara dönüşür, ancak tüm işlevsellik miras aldığı soyut sınıftadır. Buna bir örnek olarak Java'da StringBuilder'a göz atın - yalnızca oldukça kurucu değil, ancak yöntemlerin kendisinde çok fazla mantık bulmaya zorlandım (her şey AbstractStringBuilder'da).

Bu kötü bir şey değildir ve kesinlikle bir anti-kalıp değildir (ve bazı dillerde bir kalıp olabilir).


2

Düşünebildiğim bu alt sınıfların en yaygın kullanımı istisna hiyerarşileridir, ancak bu, dil yapıcıları devraldığı sürece, sınıfta genellikle hiçbir şey tanımlayamayacağımız dejenere bir durumdur. Kalıtımın bunun ReadErrorözel bir durum olduğunu ifade etmek için kullanıyoruz IOError, ancak ReadErrorhiçbir yöntemi geçersiz kılmanıza gerek yok IOError.

Bunu yapıyoruz, çünkü istisnalar türlerini kontrol ederek yakalanıyor. Bu nedenle, türdeki uzmanlığı kodlamak zorundayız ki birileri isterse ReadErrorhepsini yakalamadan yakalayabilsin IOError.

Normalde, bir şeyleri kontrol etmek korkunç derecede kötü bir formdur ve bundan kaçınmaya çalışırız. Bundan kaçınmayı başarırsak, o zaman tip sistemindeki uzmanlıkları ifade etmek için gerekli bir gerek yoktur.

Yine de, örneğin, türün adı nesnenin kayıtlı dizgisi biçiminde göründüğünde yine de yararlı olabilir: bu dildir ve muhtemelen çerçeveye özgüdür. Sen prensipte biz bu durumda sınıfın bir yöntemi çağrısı ile bu tür sistemde türünün adını yerini alabilecek ediyorum daha sadece yapıcı daha geçersiz SystemDataHelperBuilder, biz de geçersiz olur loggingname(). Eğer sisteminizde böyle bir giriş varsa, sınıfınız kelimenin tam anlamıyla yapıcıyı geçersiz kılsa da, "ahlaki olarak" da sınıf adını geçersiz kıldığını ve pratik amaçlar için yalnızca kurucu alt sınıfı olmadığını hayal edersiniz. Arzu edilen farklı davranışlar var, '

Bu nedenle, kodunun başka yerde bir şekilde kontrol ettiği, örneğin SystemDataHelperBuilderbir şubeyle (türüne göre dalları yakalamak istisna gibi) veya belki de sonuçlanacak genel bir kod olduğu için kodunu iyi bir fikir olabilir ismi SystemDataHelperBuilderyararlı bir şekilde kullanmak (sadece kayıt olsa bile).

Bununla birlikte, özel durumlar için türlerin kullanılması bazı karışıklıklara yol açmaktadır, çünkü eğer herhangi bir şekilde farklı davranırlarsa ImmutableRectangle(1,1)ve sonunda birileri neden ve belki de istememesini merak eder. İstisna hiyerarşilerinden farklı olarak, bir dikdörtgenin kare olup olmadığını kontrol ederek birlikte olup olmadığını kontrol edin . Örneğinizde, aynı argümanlarla yaratılan a ile a arasında bir fark vardır ve bu problemlere neden olabilir. Bu nedenle, "doğru" argümanlarla oluşturulan bir nesneyi döndürme işlevi bana normalde yapılacak doğru şeyi gösterir: alt sınıf "aynı" şeyin iki farklı temsiline yol açar ve yalnızca siz bir şeyi yapıyorsanız yardımcı olur normalde yapmamaya çalışacağım.ImmutableSquare(1)height == widthinstanceofSystemDataHelperBuilderDataHelperBuilder

Not ben ediyorum değil ben bir programcı hiç düşünmediği tüm iyi ve kötü fikirlerin bir kategori sağlamaktadır mümkün olduğuna inanmıyorum, çünkü tasarım desenleri ve anti-desen açısından konuşurken. Bu nedenle, her fikir bir kalıp ya da kalıp karşıtı değildir, sadece biri farklı bağlamlarda tekrar tekrar meydana geldiğini tespit ettiğinde ve isimlendirdiğinde ;-) bu tür bir alt sınıflandırma için özel bir isim bilmiyorum.


Kullanımlarını , içeriğini mümkün olduğunca mümkün kılmak ImmutableSquareMatrix:ImmutableMatrixiçin etkili bir yöntem istemek şartıyla, görebiliyordum . Olsa bile bir temelde olan yapıcı bu yükseklik ve genişlik eşleşme ve gerekli yöntemi sadece (yerine örneğin bir inşa daha kendini dönmek aynı sırt dizi sarar olan), böyle bir tasarım kare gerektiren yöntemler için derleme parametre doğrulamasını sağlayacak matrislerImmutableMatrixImmutableSquareMatrixImmutableSquareMatrixImmutableMatrixAsSquareMatrixImmutableSquareMatrix
SuperCat

@supercat: iyi nokta, ve sorgulayıcı örneğinde, bir fonksiyonun geçirilmesi gereken fonksiyonlar varsa SystemDataHelperBuilderve sadece herhangi birinin DataHelperBuilderyapması gerekmiyorsa , bunun için bir tip tanımlamak mantıklıdır (ve DI'yi bu şekilde ele aldığınızı varsayarak). . Örneğinizde, bir kare matrisin determinant gibi kare olmayan bir yapıda olamayacağı bazı işlemler var, ancak sisteminiz tipine göre kontrol etmek isteyeceğiniz sistemlere ihtiyaç duymasa bile iyi .
Steve Jessop

... bu yüzden söylediklerimin tam olarak doğru olmadığını varsayalım , “bir dikdörtgenin kare olup olmadığını kontrol ederek, olup olmadığını kontrol ederek kontrol height == widthedin instanceof”. Statik olarak iddia edebileceğiniz bir şeyi tercih edebilirsiniz.
Steve Jessop

Yapıcı sözdizimi gibi bir şey statik fabrika yöntemleri çağırmak için izin verecek bir mekanizma olsaydı keşke. İfadenin türü, kendisinden bile foo=new ImmutableMatrix(someReadableMatrix)daha açıktır , ancak sonraki formlar, eskilerin sahip olmadığı yararlı anlamsal olanaklar sunar; eğer yapıcı matrisin kare olduğunu söyleyebilirse, türünün yeni bir nesne örneği yapmak için kare bir matris gerektiren aşağı akış yönünde kod gerektirmekten daha temiz olabileceğini yansıtması. someReadableMatrix.AsImmutable()ImmutableMatrix.Create(someReadableMatrix)
Supercat

@supercat: Python ile ilgili sevdiğim küçük bir şey bir newoperatörün olmaması . Bir sınıf yalnızca çağrılabilirdir, çağrıldığında (varsayılan olarak) kendi örneğini döndürür. Bu yüzden, arayüz tutarlılığını korumak istiyorsanız, ismi büyük harfle başlayan bir fabrika fonksiyonunu yazmak mükemmel şekilde mümkündür, bu yüzden sadece bir kurucu çağrısına benziyor. Bunu rutin olarak fabrika fonksiyonları ile yaptığım için değil, ihtiyacınız olduğunda oradadır.
Steve Jessop

2

Bir alt sınıf ilişkisinin en katı Nesne Yönelimli tanımı “is-a” olarak bilinir. Bir kare ve dikdörtgenin geleneksel örneğini kullanarak, bir kare «is-a» bir dikdörtgendir.

Bununla, bir "is-a" nın kodunuz için anlamlı bir ilişki olduğunu düşündüğünüz herhangi bir durum için alt sınıflamayı kullanmalısınız.

Özel bir alt sınıf durumunuzda, bir kurucudan başka bir şey olmadan, onu “bir” is perspektifinden analiz etmelisiniz. Bir SystemDataHelperBuilder «'in-a» DataHelperBuilder olduğu açıktır, bu nedenle ilk geçiş geçerli bir kullanım olduğunu öne sürer.

Cevaplamanız gereken soru, diğer kodlardan herhangi birinin bu «bir-a» ilişkisinden yararlanıp yararlanmadığıdır. Başka bir kod, SystemDataHelperBuilders'ı, genel DataHelperBuilders popülasyonundan ayırt etmeye çalışıyor mu? Eğer öyleyse, ilişki oldukça makul ve alt sınıfı korumalısınız.

Bununla birlikte, eğer başka bir kod bunu yapmazsa, sahip olduğunuz bir "is-a" ilişkisi olabilecek ya da bir fabrika ile uygulanabilecek bir ilişkidir. Bu durumda, her iki yönde de gidebilirsiniz, ancak “is-a” ilişkisi yerine bir Fabrika öneririm. Başka bir kişi tarafından yazılan Nesne Yönelimli kodu analiz ederken, sınıf hiyerarşisi önemli bir bilgi kaynağıdır. Kodu anlamalarını sağlayacak «is-a» ilişkilerini sağlar. Buna göre, bu davranışı bir alt sınıfa koymak, "birisinin üst sınıfın yöntemlerini araştırıp kazanamayacağı bir şey" den "davranışını" herkesin koda girmeden önce bakacakları bir şeye "terfi ettirir. Guido van Rossum'dan "kod, yazıldığından daha sık okunur" kodunuzu yaklaşan geliştiriciler için okunabilirliği azaltmak bu yüzden ödemek için katı bir fiyattır. Bir fabrika kullanabilirsem, ödememeyi seçerdim.


1

Alt türünün bir örneğini her zaman alt türün bir örneğiyle değiştirebildiğiniz ve her şeyin hala doğru şekilde çalışabildiğiniz sürece, alt tür hiçbir zaman "yanlış" değildir. Bu, alt sınıf, süper tipin verdiği garantilerin hiçbirini zayıflatmaya çalışmadığı sürece kontrol eder. Daha güçlü (daha spesifik) garantiler verebilir, bu nedenle iş arkadaşınızın sezgisi doğrudur.

Buna bakıldığında, yaptığınız alt sınıf muhtemelen yanlış değildir (ne yaptıklarını tam olarak bilmediğim için, kesin olarak söyleyemem.) Kırılgan temel sınıf sorununa karşı temkinli olmalısınız ve ayrıca bir interfaceavantajın size fayda sağlayıp sağlayamayacağını düşünün, ancak bu tüm miras kullanımları için geçerlidir.


1

Bence bu soruyu cevaplamanın anahtarı bu konuya, özel kullanım senaryosuna bakmak.

Kalıtım, bağlantı dizesi gibi veritabanı yapılandırma seçeneklerini zorlamak için kullanılır.

Bu bir anti örüntüdür, çünkü sınıf Tek Sorumluluk Sorumlusu ihlal ediyor - Kendisini o yapılandırmanın belirli bir kaynağı ile yapılandırıyor ve "Bir şey yapmak ve iyi yapmak" şeklinde değil. Bir sınıfın yapılandırması, sınıfın içine girmemelidir. Veritabanı bağlantı dizgilerini ayarlamak için, çoğu zaman uygulamanın başlatıldığı sırada gerçekleşen bir olay sırasında uygulama düzeyinde gerçekleştiğini gördüm.


1

Yapıcıyı yalnızca farklı kavramları ifade etmek için düzenli olarak alt sınıflar kullanıyorum.

Örneğin, aşağıdaki sınıfı göz önünde bulundurun:

public class Outputter
{
    private readonly IOutputMethod outputMethod;
    private readonly IDataMassager dataMassager;

    public Outputter(IOutputMethod outputMethod, IDataMassager dataMassager)
    {
        this.outputMethod = outputMethod;
        this.dataMassager = dataMassager;
    }

    public MassageDataAndOutput(string data)
    {
        this.outputMethod.Output(this.dataMassager.Massage(data));
    }
}

Daha sonra bir alt sınıf oluşturabiliriz:

public class CapitalizeAndPrintOutputter : Outputter
{
    public CapitalizeAndPrintOutputter()
        : base(new PrintOutputMethod(), new Capitalizer())
    {
    }
}

Daha sonra, CapitalizeAndPrintOutputter'ı kodunuzun herhangi bir yerinde kullanabilir ve tam olarak ne tür bir çıktı olduğunu bilirsiniz. Ayrıca, bu desen aslında bu sınıfı oluşturmak için bir DI konteynerini kullanmayı çok kolaylaştırıyor. DI kapsayıcısı PrintOutputMethod ve Capitalizer hakkında bir şey biliyorsa, sizin için otomatik olarak CapitalizeAndPrintOutputter uygulamasını da oluşturabilir.

Bu modeli kullanmak gerçekten oldukça esnek ve kullanışlıdır. Evet, olabilir aynı şeyi yapmak için fabrika yöntemleri kullanın ama sonra (C # en azından) Tür sisteminin gücünün bir kısmını kaybeder ve kesinlikle DI kapları kullanarak daha fazla hantal hale gelir.


1

İlk önce, kod yazılırken, alt sınıfın, başlangıçtaki iki alanın da her ikisi de müşteri koduyla ayarlanabildiği için, üst öğeden daha belirgin olmadığını unutmayın.

Alt sınıfın bir örneği yalnızca bir downcast kullanılarak ayırt edilebilir.

Şimdi, DatabaseEngineve ConnectionStringözelliklerinin alt sınıf tarafından yeniden uygulandığı, buna erişen bir tasarıma Configurationsahipseniz, o zaman alt sınıfa sahip olmak daha mantıklı olan bir kısıtlamaya sahip olursunuz.

"Anti-patern" in zevkime göre çok güçlü olduğunu söyleyerek; Burada gerçekten yanlış bir şey yok.


0

Verdiğiniz örnekte eşiniz haklı. İki veri yardımcı kurucuları stratejilerdir. Biri diğerinden daha spesifik, ancak ikisi de başlatıldıktan sonra değiştirilebilir.

Temel olarak, veri kurucu üreticisinin bir müşterisi systemdatahelperbuilder'ı almak olsaydı, hiçbir şey bozulmazdı. Diğer bir seçenek, systemdatahelperbuilder'ın datahelperbuilder sınıfının statik bir örneği olması olabilirdi.

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.