“Mirasa ilişkin kompozisyon” “kuru ilke” yi ihlal ediyor mu?


36

Örneğin, diğer sınıfların genişletmesi için bir sınıfım olduğunu düşünün:

public class LoginPage {
    public String userId;
    public String session;
    public boolean checkSessionValid() {
    }
}

ve bazı alt sınıflar:

public class HomePage extends LoginPage {

}

public class EditInfoPage extends LoginPage {

}

Aslında, alt sınıfın geçersiz kılacak bir yöntemi yoktur, Ana Sayfa'ya da genel bir şekilde erişemem, yani: Şunun gibi bir şey yapmazdım:

for (int i = 0; i < loginPages.length; i++) {
    loginPages[i].doSomething();
}

Sadece giriş sayfasını tekrar kullanmak istiyorum. Ancak https://stackoverflow.com/a/53354’e göre buradaki kompozisyonu tercih etmeliyim çünkü LoginPage arayüzüne ihtiyacım yok, bu yüzden miras kullanmıyorum:

public class HomePage {
    public LoginPage loginPage;
}

public class EditInfoPage {
    public LoginPage loginPage;
}

fakat sorun buraya gelir, yeni sürümde kod:

public LoginPage loginPage;

yeni bir sınıf eklendiğinde çoğaltılır. LoginPage'in ayarlayıcı ve alıcıya ihtiyacı varsa, daha fazla kodun kopyalanması gerekir:

public LoginPage loginPage;

private LoginPage getLoginPage() {
    return this.loginPage;
}
private void setLoginPage(LoginPage loginPage) {
    this.loginPage = loginPage;
}

Öyleyse benim sorum şu, “mirasa ilişkin kompozisyon” “kuru ilkeyi” ihlal ediyor mu?


13
Bazen mirasa veya bileşime ihtiyaç duymazsınız, bu da bazen birkaç nesneye sahip bir sınıfın işi yaptığını söyler.
Erik Eidt

23
Neden tüm sayfalarınızın giriş sayfası olmasını istersiniz? Belki sadece bir giriş sayfam var.
Bay Cochese,

29
Ancak, miras ile birlikte, extends LoginPageher yere kopyaladınız . ŞAH MAT!
el.pescado

2
Son snippet'te çok fazla sorun yaşıyorsanız alıcıları ve ayarlayıcıları fazla kullanıyor olabilirsiniz. Kapsülleme ihlal eğilimindedirler.
Brian McCutchon

4
Böylece, sayfanızın dekore edilmesini ve LoginPagebir dekoratörün olmasını sağlayın . Artık çoğaltma yok, sadece basit page = new LoginPage(new EditInfoPage())ve bitirdiniz. Veya herhangi bir sayfaya dinamik olarak eklenebilecek kimlik doğrulama modülünü yapmak için açık-kapalı prensibini kullanırsınız. Çoğunlukla yeni bir soyutlama bulmak için kod çoğaltmayla baş etmenin birçok yolu vardır. LoginPageBüyük olasılıkla hatalı bir addır, emin olmak istediğiniz, kullanıcının bu sayfaya göz atarken kimliğini doğrulaması , yönlendirilirken LoginPageveya doğru değilse bir hata mesajı göstermesidir.
Polygnome

Yanıtlar:


46

Bekle, tekrarladığın için endişeleniyorsun.

public LoginPage loginPage;

iki yerde DRY ihlal ediyor? Bu mantıkla

int x;

şimdi tüm kod tabanında yalnızca bir nesnede var olabilir. Bleh.

KURU akılda tutulması gereken iyi bir şey ama hadi. dışında

... extends LoginPage

alternatifinizde kopyalanıyor, bu yüzden DRY konusunda anal olmak bile bunu anlamıyor.

Geçerli DRY endişeleri, birden fazla yerde tanımlanmış birden fazla yerde ihtiyaç duyulan özdeş davranışa odaklanma eğilimindedir; öyle ki, bu davranışı değiştirme ihtiyacı birden fazla yerde değişiklik yapılmasını gerektirir. Tek bir yerde kararlar alın, yalnızca bir yerde onları değiştirmeniz gerekecektir. Bu, sadece bir nesnenin LoginPage'inize referans alabileceği anlamına gelmez.

KURU kör olarak takip edilmemelidir. Kopyalama ve yapıştırma işleminin iyi bir yöntem veya sınıf adı düşünmekten daha kolay olduğu için çoğaltıyorsanız, muhtemelen yanlışsınız demektir.

Ancak aynı kodu farklı bir yere koymak istiyorsanız, çünkü bu farklı yer farklı bir sorumluluğa tabidir ve bağımsız olarak değişmesi muhtemeldir, o zaman muhtemelen DRY uygulamanızı rahatlatmak ve bu özdeş davranışın farklı bir kimliğe sahip olmasını sağlamak akıllıca olacaktır. . Sihirli sayıları yasaklayan aynı düşünce tarzı.

DRY sadece kodun neye benzediği ile ilgili değil. Bir fikrin ayrıntılarını, akılsız tekrarlama ile yaymak değil, bakıcıları akılsız tekrarlamayı kullanarak işleri düzeltmeye zorluyor. Kendine, akılsız tekrarlamanın sadece işlerin gerçekten kötü bir şekilde yapıldığını kabul ettiğini kabul etmeye başladığın zamandır.

Gerçekten şikayet etmeye çalıştığını düşündüğüm şeye "boilerplate kodu" deniyor. Evet, kalıtım yerine kompozisyon kullanmak için boyler kodu gerekir. Hiçbir şey ücretsiz olarak açığa çıkmaz, açıklayan bir kod yazmanız gerekir. Bu kazan plakasıyla durum esnekliği, maruz kalan arayüzü daraltma, nesnelere soyutlama seviyelerine uygun farklı isimler verme, iyi ol dolaylılığı ve dışarıdan değil, dışardan oluşturduğunuzu kullanıyorsunuz. içeride, yani normal arayüzle karşı karşıya geliyorsun.

Ama evet, çok fazladan klavye yazıyor. Yo-yo'yu bir miras yığınında aşağı yukarı zıplatma problemini önleyebildiğim sürece, buna değer kodu okuduğumda.

Şimdi miras almayı reddettiğimden değil. Favori kullanımlarımdan biri istisnalara yeni isimler vermektir:

public class MyLoginPageWasNull extends NullPointerException{}

int x;Bir kod temeli içinde sıfırdan fazla olamaz
K. Alan Bates

@ K.AlanBates affedersiniz ?
candied_orange

... Point Class lol ile retort olacağını biliyordum. Point sınıfını kimse umursamıyor. Eğer kod üssünüze girersem ve int a; int b; int x;'seni' kaldırmaya zorlayacağımı görürsünüz .
K. Alan Bates,

@ K.AlanBates Vay. Bu tür bir davranışın sizi iyi bir kodlayıcı yapabileceğini düşünmeniz üzücü. En iyi kodlayıcı, başkalarıyla ilgili en fazla şeyleri budalabileceğiniz şey değil. Gerisini daha iyi yapan şey bu.
candied_orange

Anlamsız isimler kullanmak bir başlangıç ​​değildir ve bu kodun geliştiricisini bir varlıktan çok bir sorumluluk haline getirir.
K. Alan Bates

127

DRY ilkesiyle ilgili yaygın bir yanlış anlaşılma, bir şekilde kod satırlarının tekrarlanmamasıyla ilgili olmasıdır. KURU ilkesi, "Her bilgi parçasının bir sistem içinde tek, kesin ve yetkili bir temsiline sahip olması gerekir" şeklindedir . Bilgi ile ilgili, kodla değil.

LoginPageGiriş yapmak için sayfanın nasıl çizileceğini biliyor. Eğer EditInfoPagenasıl yapılacağını bilseydi, bu bir ihlal olurdu. LoginPageKompozisyonla dahil olmak hiçbir şekilde DRY ilkesinin ihlali değildir .

DRY ilkesi, yazılım mühendisliğinde belki de en kötüye kullanılan ilkedir ve her zaman kodu çoğaltmak için bir ilke olarak değil, soyut alan bilgisini çoğaltmamak için bir ilke olarak düşünülmelidir. Aslında, çoğu durumda DRY'yi doğru uygularsanız, o zaman kodu kopyalayacaksınız ve bu mutlaka kötü bir şey değil.


27
"Tek sorumluluk ilkesi" çok daha fazla suiistimal edildi. "Kendini tekrar etme" kolayca iki numara olarak gelebilir :-)
gnasher729

28
"KURU", bir alıcı ifadesi olan "Kendinizi Tekrar Etme" nin kullanışlı bir kısaltmasıdır, ancak ilkenin adı değil , ilkenin gerçek adı, bir kez akılda kalıcı bir addır. açıklaması için birkaç paragraf alır bir ilke için. Önemli olan, paragraf çift anlamaktır değil üç harf D, R, ve Y. ezberlemeye
Jörg W Mittag

4
@ gnasher729 Biliyor musun, aslında ben de seninle SRP’nin çok daha fazla suistimal edildiğine katılıyorum. Adil olmakla birlikte, çoğu durumda bunların birlikte kötüye kullanıldığını düşünüyorum. Teorim, programcıların kısaltmaları “kolay adlarla” kullanmaları konusunda güvenilmemeleri gerektiğidir.
wasatz

17
IMHO bu iyi bir cevap. Ancak, adil olmak gerekirse: Tecrübeme göre, DRY ihlallerinin en sık görülen şekli kopyala-yapıştır programlaması ve sadece kodu kopyalamaktan kaynaklanıyor. Birisi bana bir keresinde “ne zaman bir kodu kopyalayıp yapıştırırsanız, kopyalanan kısmın ortak bir işleve verilemediğini iki kez düşünün” demişti - ki bu IMHO'nun çok iyi bir tavsiyesiydi.
Doktor Brown,

9
Kopyala-yapıştırın kötüye kullanılması kesinlikle DRY'yi ihlal etmek için bir itici güçtür, ancak basitçe kopyala-yapıştırmayı yasaklamak DRY'yi takip etmek için kötü bir rehberdir. Bu yöntemler farklı bilgi parçalarını temsil ettiğinde aynı kodla iki yönteme sahip olduğum için hiç pişmanlık duymam. İki farklı sorumluluğa hizmet ederler. Bugün sadece aynı kodlara sahipler. Bağımsız olarak değişmekte özgür olmalılar. Evet, bilgi, kod değil. Peki. Diğer cevaplardan birini yazdım ama buna boyun eğeceğim. +1.
candied_orange

12

Kısa cevap: evet, öyle - bazı küçük, kabul edilebilir derecede.

İlk bakışta, miras bazen size bazı kod satırları kazandırabilir, çünkü "yeniden kullanma sınıfım tüm genel yöntemleri ve nitelikleri 1: 1 şekilde içerecektir" deme etkisine sahiptir. Öyleyse, bir bileşendeki 10 yöntemin listesi varsa, devralınan sınıfta bunları kodda tekrarlamak zorunda değilsiniz. Bir kompozisyon senaryosunda, bu 10 yöntemin 9'unun bir yeniden kullanım bileşeni aracılığıyla kamuya açık olarak maruz kalması gerektiğinde, 9 delegasyon çağrısı yazması ve kalanını bırakması gerektiğinden, bunun hiçbir yolu yoktur.

Bu neden tolere edilebilir? Kompozisyon senaryosunda çoğaltılan yöntemlere bakın - bu yöntemler yalnızca bileşenin arayüzüne çağrı gönderir, bu nedenle gerçek bir mantık içermez.

DRY prensibinin kalbi, aynı mantıksal kuralların kodlandığı iki yerde koddan kaçınmaktan kaçınmaktır; çünkü bu mantıksal kurallar değiştiğinde, DRY olmayan kodda, bu yerlerden birini uyarlamak ve diğerini unutmak kolaydır, bu bir hata veriyor.

Ancak delegasyon çağrıları mantık içermediğinden, bunlar normalde böyle bir değişikliğe tabi değildir, bu nedenle "kalıtım yerine kompozisyonu tercih ederken" gerçek bir soruna neden olmaz. Bileşenin arayüzü, bileşeni kullanan tüm sınıflarda resmi değişikliklere neden olabilecek değişmiş olsa bile, derlenmiş bir dilde derleyici, arayanlardan birini değiştirmeyi unuttuğumuzda bize söyleyecektir.

Örneğinize bir not: Sizin HomePageve EditInfoPagegörünüşünüzün nasıl göründüğünü bilmiyorum , ancak oturum açma işlevine sahiplerse ve HomePage(veya bir EditInfoPage) a ise LoginPage , kalıtım burada doğru araç olabilir. Kompozisyonun daha açık bir şekilde daha iyi bir araç olacağı daha az tartışılabilir bir örnek, muhtemelen olayları daha açık hale getirecektir.

Ne varsa, HomePagene EditInfoPagede bir LoginPagevarsayalım ve kişi, yazdığınız gibi, ikincisini yeniden kullanmak istiyorsa, birinin LoginPageher şeyin değil, sadece bazı kısımlarını gerektirmesi muhtemeldir . Bu durumda, kompozisyonu gösterilen şekilde kullanmaktan daha iyi bir yaklaşım olabilir.

  • yeniden kullanılabilir parçasını LoginPagekendi bileşenine almak

  • o bileşeni tekrar kullanın HomePageve EditInfoPageşimdi içinde kullanıldığı şekildeLoginPage

Bu şekilde, genellikle kalıtım konusundaki kompozisyonun neden ve ne zaman doğru yaklaşım olduğu açıkça anlaşılacaktır.

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.