KURU prensibinin yorumlanması


10

Şu anda kodlamamda bu DRY (Kendinizi Tekrarlama) konseptiyle mücadele ediyorum. Çok karmaşık hale gelmesinden korktuğum bu işlevi yaratıyorum ama KURU ilkesini izlemeye çalışıyorum.

createTrajectoryFromPoint(A a,B b,C c,boolean doesSomething,boolean doesSomething2)

Söylediğim bu işlev 3 giriş parametresi alır ve boolean kombinasyonları göz önüne alındığında işlev biraz farklı bir şey yapar doesSomethingve doesSomething2. Ancak yaşadığım sorun, bu işlev eklenen her yeni boolean parametresi ile büyük ölçüde karmaşıklık büyüyor olmasıdır.

Benim sorum şu, aynı mantığın çoğunu paylaşan bir grup farklı fonksiyona sahip olmak (bu nedenle KURU prensibini ihlal etmek) veya bir dizi parametre verildiğinde biraz farklı davranan ancak çok daha karmaşık hale getiren bir fonksiyona sahip olmak daha iyidir (ancak KURU koruyor)?


3
Paylaşılan / ortak mantık, farklı kamusal createTrajectory...işlevlerin çağırdığı özel işlevlere dönüştürülebilir mi?
SinirliWithFormsDesigner

Olabilir, ancak bu özel işlevlerin hala bu boole parametrelerini alması gerekir
Albinoswordfish

2
Bence bir çeşit somut örnek göz önüne alındığında, bunun cevaplanması çok daha kolay olacaktır. Benim ani tepkim, tasvir ettiğiniz ikilikin tamamen gerçek olmadığıdır - yani, sadece iki seçenek değildir. Bir yana, ben herhangi bir kullanımını booleanen iyi şüpheli bir parametre olarak düşünün .
Jerry Coffin


Neden koşullu şeyleri kendi işlevlerine dahil etmiyorsunuz?
Rig

Yanıtlar:


19

boolean argümanları tek bir işlev / yöntemde farklı kod yollarını tetiklemek için korkunç bir kod kokusu .

Yaptığınız şey öncelikli olarak DRY'den çok daha önemli olan Gevşek Bağlanma ve Yüksek Uyum ve Tek Sorumluluk ilkelerini ihlal ediyor .

Bu, şeylerin yalnızca ( Kuplaj ) gerektiğinde başka şeylere bağlı olması gerektiği ve bir şey ve sadece bir şey (çok iyi) yapmaları gerektiği anlamına gelir ( Uyum ).

Kendi ihmalinizle, bu çok sıkı bir şekilde bağlıdır (tüm boolean bayrakları, en kötülerinden biri olan bir tür devlet bağımlılığıdır!) Ve birbirine karışan çok fazla bireysel sorumluluğa sahiptir (aşırı karmaşık).

Yaptığınız şey zaten DRY'nin ruhunda değil . KURU daha çok tekrarlama ile ilgilidir ( Rkısaltmasıdır REPEAT). Kopyalama ve yapıştırmadan kaçınmak en temel biçimidir. Yaptığınız şey tekrarlama ile ilgili değil.

Sorununuz, kodunuzun ayrıştırılmasının doğru düzeyde olmamasıdır. Yinelenen kodunuz olacağını düşünüyorsanız, kopyalanıp yapıştırılamayan, uygun şekilde parametrelendirilen kendi işlevi / yöntemi olmalı ve diğerleri açıklayıcı olarak adlandırılmalı ve çekirdek işleve / yönteme delege edilmelidir.


Tamam, yazdığım yolun çok iyi olmadığı anlaşılıyor (ilk
şüphem)


4

İşlevi farklı şeyler yapmak için booleans'ten geçiyor olmanız Tek Sorumluluk İlkesinin ihlalidir. Bir işlev bir şey yapmalıdır. Sadece bir şey yapmalı ve iyi yapmalı.

Açıklayıcı adlarla birkaç küçük işleve bölmeniz ve bu booleanların değerlerine karşılık gelen kod yollarını ayırmanız gerektiği gibi kokuyor.

Bunu yaptıktan sonra, sonuçta ortaya çıkan işlevlerde ortak kodu aramalı ve bunu kendi işlev (ler) ine katlamalısınız. Bu şeyin ne kadar karmaşık olduğuna bağlı olarak, bir veya iki sınıfı bile hesaba katabilirsiniz.

Tabii ki, bu bir sürüm kontrol sistemi kullandığınızı ve iyi bir test takımına sahip olduğunuzu varsayar, böylece bir şeyi kırma korkusu olmadan yeniden düzenleme yapabilirsiniz.


3

Bir şey ya da bir şey yapmaya karar vermeden önce neden işlevinizdeki tüm mantığı içeren başka bir işlev oluşturmuyorsunuz2:

createTrajectoryFromPoint(A a,B b,C c){...}

dosomething(A a, B b, C c){...}

dosomething2(A a, B b, C c){...}

Ve şimdi üç farklı parametre tipini üç farklı işleve geçirerek, tekrar kendinizi tekrar edeceksiniz, bu yüzden A, B, C içeren bir yapı veya sınıf tanımlamanız gerekir.

Alternatif olarak A, B, C parametrelerini ve yapılacak işlemlerin listesini içeren bir sınıf oluşturabilirsiniz. Nesneye işlemleri kaydederek bu parametrelerle (A, B, C) gerçekleşmesini istediğiniz işlemleri (bir şey, bir şey2) ekleyin. Sonra nesnenizdeki tüm kayıtlı işlemleri çağırmak için bir yöntem var.

public class MyComplexType
{
    public A a{get;set;}
    public B b{get;set;}
    public C c{get;set;}

    public delegate void Operation(A a, B b, C c);
    public List<Operation> Operations{get;set;}

    public MyComplexType(A a, B b, C c)
    {
        this.a = a;
        this.b = b;
        this.c = c   
        Operations = new List<Operation>();
    }

    public CallMyOperations()
    {
        foreach(var operation in Operations)
        {
            operation(a,b,c);
        }
    }
}

Booleans dosomething ve dosomething2 için olası değer kombinasyonlarını hesaba katmak için, temel createTrajectoryFromPoint işlevine ek olarak 2 değil 4 fonksiyona ihtiyacınız olacaktır. Bu yaklaşım, seçeneklerin sayısı arttıkça iyi ölçeklenmez ve işlevlerin adlandırılması bile yorucu hale gelir.
JGWeissman

2

DRY çok ileri götürülebilir, en iyisi DRY ile birlikte tek sorumluluk ilkesini (SRP) kullanmaktır. Aynı kodun biraz farklı sürümlerini yapmak için bir işleve bool bayrakları eklemek, bir işlevle çok fazla yaptığınız bir işaret olabilir. Bu durumda, bayraklarınızın temsil ettiği her durum için ayrı bir işlev oluşturmayı öneririm, o zaman her bir işlevi yazdığınızda, tüm bayrakları geçmeden özel bir işleve taşınabilecek ortak bir bölüm varsa oldukça açık olmalıdır. , kodun belirgin bir bölümü yoksa, gerçekten kendinizi tekrarlamıyorsunuz, birkaç farklı ama benzer durumunuz var.


1

Genellikle bu sorunla birkaç adım atıyorum, ne zaman daha ileri gidileceğini anlayamadığımda duruyorum.

İlk olarak, yaptıklarınızı yapın. DRY ile zorlanın. Eğer varsa yok kıllı karmaşa ile bitirmek, bitirdiniz. Sizin durumunuzda olduğu gibi, yinelenen kodunuz yoksa ancak her boole değeri 20 farklı yerde kontrol edilmişse, bir sonraki adıma geçin.

İkinci olarak, kodu bloklara ayırın. Booleanların her biri, çalıştırmayı sağ bloğa yönlendirmek için sadece bir kez (belki de bazen iki kez) refere edilir. İki boolean ile dört blokla karşılaşırsınız. Her blok neredeyse aynıdır. KURU gitti. Her bloğu ayrı bir yöntem yapmayın . Bu daha zarif olurdu, ancak tüm kodu bir yönteme koymak, bakım yapan herkesin her değişikliği dört yerde yapması gerektiğini görmesini kolaylaştırır, hatta mümkün kılar. İyi organize edilmiş kod ve uzun bir monitörle, farklar ve hatalar neredeyse açık olacaktır. Artık korunabilir kodunuz var ve orijinal karışık karmaşadan daha hızlı çalışacak.

Üçüncüsü, bloklarınızın her birinden yinelenen kod satırları tutmaya ve bunları güzel, basit yöntemlere dönüştürmeye çalışın. Bazen hiçbir şey yapamazsınız. Bazen fazla bir şey yapamazsınız. Ancak yaptığınız her küçük parça sizi KURU'ya geri götürür ve kodu takip etmeyi biraz daha kolay ve daha güvenli hale getirir. İdeal olarak, orijinal yönteminiz yinelenen kod içermeyebilir. Bu noktada, boole parametreleri olmadan birkaç yönteme bölmek isteyebilirsiniz veya edemeyebilirsiniz. Arama kodunun rahatlığı artık ana endişe kaynağıdır.

İkinci adım yüzünden cevabımı çoktan buraya ekledim. Yinelenen koddan nefret ediyorum, ancak bir sorunu çözmenin tek anlaşılabilir yolu varsa, bunu herkesin ne yaptığınızı bir bakışta bileceği şekilde yapın. Birden çok blok ve yalnızca bir yöntem kullanın. Blokları adlar, boşluklar, hizalamalar, ... her şeyde mümkün olduğunca aynı yapın. Farklılıklar daha sonra okuyucuya atlamalıdır. KURU bir şekilde nasıl yeniden yazıldığını açıklığa kavuşturabilir ve eğer değilse, sürdürmek makul derecede basit olacaktır.


0

Alternatif bir yaklaşım, boolean parametrelerini arayüz parametreleriyle değiştirmektir, arayüz uygulamalarında yeniden düzenlenmiş farklı boolean değerlerini işlemek için kod ile. Böylece

createTrajectoryFromPoint(A a,B b,C c,IX x,IY y)

burada booleanlar için farklı değerleri temsil eden IX ve IY uygulamalarınız vardır. Fonksiyonun bedeninde, nerede olursanız olun

if (doesSomething)
{
     ...
}
else
{
     ...
}

bunu, atlanan kod bloklarını içeren uygulamalarla IX'da tanımlanan bir yönteme yapılan bir çağrı ile değiştirirsiniz.

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.