Kalıtım üzerine kompozisyon ama


13

Kendime yazılım mühendisliğini öğretmeye çalışıyorum ve beni şaşırtan bazı çelişkili bilgilere karşı geliyorum.

OOP ve soyut sınıfların / arayüzlerin ne olduğunu ve nasıl kullanıldığını öğreniyorum, ama sonra 'kompozisyonu kalıtımdan yana tutması' gerektiğini okuyorum. Kompozisyon, bir sınıfın bu yeni nesnenin işlevselliğini kullanmak / etkileşimde bulunmak için başka bir sınıfın nesnesini oluşturması / oluşturmasıdır.

Yani sorum şu: Soyut sınıfları ve arayüzleri kullanmam gerekiyor mu? Soyut bir sınıf yaratmamak ve bu soyut sınıfın somut sınıflardaki işlevselliğini genişletmek / miras almak ve bunun yerine diğer sınıfın işlevselliğini kullanmak için yeni nesneler oluşturmak mı?

Veya kompozisyon kullanmalı mıyım ve soyut sınıflardan miras almalıyım; ikisini de birbirleriyle birlikte mi kullanıyorsunuz? Öyleyse, bunun nasıl çalışacağına ve faydalarına ilişkin bazı örnekler verebilir misiniz?

PHP ile en rahat olduğum için, diğer dillere geçmeden ve yeni edinilmiş SE becerilerimi aktarmadan önce OOP / SE becerilerimi geliştirmek için kullanıyorum, bu yüzden PHP kullanan örnekler çok takdir edilecektir.


2
"Kalıtım üzerine iyilik kompozisyonu", "matkaplar üzerinde iyilik testereleri" kadar mantıklı olan saçma bir fikirdir. Bunlar, iki farklı kullanım durumunda kullanılmaya uygun olan iki farklı araçtır ve ikisini de birbirinin yerine kullanabileceğiniz zamanlar aslında oldukça nadirdir.
Mason Wheeler

2
"Y'den Y'ye Favor" hiçbir zaman Y kullanmamanız anlamına gelmez, sadece X'in daha iyi olup olmayacağını düşünün
Richard Tingle

2
"Kalıtım üzerine iyilik kompozisyonu" daha doğru bir şekilde "Asla, asla, asla miras kullanmayın" şeklinde ifade edilir, bir arayüzün uygulanmasının kalıtım olmadığını ve seçtiğiniz dilin sadece% 100'den miras kalan arayüzleri değil soyut sınıfları desteklemesi soyut sınıf da "kalıtım değil" olarak görülebilir.
David Arno

1
@MasonWheeler, miras için geçerli bir kullanım durumu yoktur. En azından "kötü" bir özellik "git" gibi.
David Arno

1
@DavidArno Bu sadece saçma. Kalıtım, tüm programlama tarihinde şimdiye kadar geliştirilen en kullanışlı, üretken özelliklerden biridir. Yararlı herhangi bir şeyde olduğu gibi, onu kötüye kullanmanın birçok yolu vardır, ancak düzgün bir şekilde kullanılması, çalışmanızın gücünü ve üretkenliğini büyük ölçüde artırır.
Mason Wheeler

Yanıtlar:


19

Kalıtım üzerinden kompozisyon, var olan bir sınıfın işlevselliğini yeniden kullanmak veya genişletmek istediğinizde, genellikle mevcut sınıfı 'saran' ve onu dahili olarak kullanacak başka bir sınıf oluşturmak daha uygun olur. Dekoratör deseni buna bir örnektir.

Kalıtım, yeniden kullanım senaryolarıyla başa çıkmak için iyi bir varsayılan yol değildir, çünkü genellikle temel sınıf işlevlerinin yalnızca bir kısmını kullanmak istersiniz ve alt sınıf, Liskov ikamesini tatmin edecek şekilde temel sınıfın tüm sözleşmesini destekleyemez. prensibi .

Şablon yöntemi , kalıtımın uygun olduğu bir duruma iyi bir örnektir.

Kompozisyon ve kalıtım arasında seçim yapma konusunda yönergeler için bu cevaba bakınız .


Bir sınıfın kısmi olarak yeniden kullanılması durumunda, kullanılmayan bölümün kalıtımdan çok kompozisyonla daha temiz göz ardı edildiğine işaret etmek için +1.
Lawrence

4

Bu dilde somut örnekler vermek için PHP'ye yeterince aşina değilim, ama işte yararlı bulduğum birkaç yönerge.

Arayüzler / özellikler , çok az ortak noktası olabilecek birçok sınıfta davranışı tanımlamak için yararlıdır.

Örneğin, bir JSON api üzerinde çalışıyorsanız, iki yöntem belirten bir arabirim tanımlayabilirsiniz: “toJson” ve “toStatusCode”. Bu, bu arabirimi uygulayan herhangi bir nesneyi alabilecek bir yardımcı yazmanıza ve bir Http yanıtına dönüştürmenize olanak tanır.

Çoğu zaman, bu doğrudan mirasa tercih edilir, çünkü sığ sınıf hiyerarşilerine yöneldiği için kırılgan taban sınıf probleminden muzdarip olma olasılığı daha düşüktür.

Doğrudan Kalıtım en iyi, zorlayıcı nedenler olmadıkça yaptığınız bir şey yerine, bunu yapmak için zorlayıcı nedenler olduğunda yaptığınız bir şey olarak düşünülür.

Arayüzlerdeki varsayılan uygulamaları desteklemeyen dillerde, bir dizi temel işlevselliği paylaşmak makul bir yol olabilir, ancak genellikle alt sınıflarla yapabileceklerinizi büyük ölçüde kısıtlar (mevcut olduğunda çoklu kalıtım nadiren acıya değer) . Genellikle, kompozisyonu kullanmak için demirbaş yönlendirme yöntemlerini yazmanın acısına değer buluyorum.

Kompozisyon varsayılan stratejiniz olmalıdır. Mümkün olduğunca arayüzlerle besteleyin ve bunları yapıcı argümanları olarak iletin. Bu, testler yazarken hayatınızı daha kolay hale getirecektir.

Çıktının bir kısmı sistem saatinin durumuna bağlıysa, beklenen ve gerçek çıktıyı karşılaştırmak doğru bir acı olduğundan, mümkün olduğunca küresel tektonlarla çalışmaktan kaçının.

Bu elbette her zaman mümkün değildir. Örneğin, Play web çerçevesi, temel olarak alana özgü bir dil olan bir JSON kütüphanesi sağlar. Bunu değiştirmek, 'Json.prettyPrint' çağrılarını değiştirmek sadece çok küçük bir parça olacak büyük bir girişim olacaktır.


1

Kompozisyon, bir sınıfın söz konusu sınıftan miras almak yerine, zaten bu işlevselliği uygulayan bir (muhtemelen dahili) sınıfı somutlaştırarak bazı işlevler sunmasıdır.

Yani, örneğin, bir gemiyi modelleyen bir sınıfınız varsa ve şimdi geminize bir helikopter pisti sunması gerektiği söylendiyse, geminizi bir helikopter pistinden (duh!) Türetmek doğal değildir. geminiz bir helikopter pisti sınıfı içerir ve bir yöntemle ortaya koyar Ship.getHelipad().

Yıllarca (on yıl kadar önce) insanlar mirasçılığı işlevselliği bir araya getirmenin hızlı ve kolay bir yolu olarak görürlerdi, bu yüzden elbette çok topal olan "helipaddan miras gemi" türünün birçok örneği vardı.

Ancak "Miras Üzerindeki Kompozisyonu İyileştirme" ifadesi, bunun bir kural değil, sadece bir öneri olduğunu açıkça ortaya koyacak şekilde dikkatle ifade edilmiştir. Dictum'un yazarı, " asla miras değil, sadece kompozisyon kullanamazsın " gibi bir şey söylemekten kaçınacak kadar dikkatliydi . Bu temel olarak, yazılım mühendisliği topluluğunun dikkatini kalıtımın aşırı kullanılmış olduğu gerçeği haline getirirken, birçok durumda kompozisyon, kalıtımdan daha net, zarif ve sürdürülebilir tasarımlar üretir.

Yani, esasen, "Miras Üzerindeki Kompozisyonu İyileştirme" ifadesi, "miras almak veya bestelemek?" soru, en uygun stratejinin ne olduğunu çok düşünmelisiniz ve en fazla şansın en uygun stratejinin kalıtım değil kompozisyon olduğu ortaya çıkmasıdır.

Ancak bu bir kural olmadığından, mirasın daha doğal olduğu birçok durum olduğunu da unutmamalısınız. Orada miras kullanmanız gereken bir kompozisyon kullanırsanız, birçok kötülük kodunuzun başına gelir.

Gemi örneğine geri dönmek için, geminizin a ile etkileşim için bir arayüz sunması gerekiyorsa FloatingMachine, o zaman onu soyut bir FloatingMachinesınıftan türetmek daha doğaldır , bu da muhtemelen başka bir soyut Machinesınıftan türetilebilir .

Kompozisyona ve miras sorusuna cevap için temel kural:

Sınıfımın göstermesi gereken arayüzle "is" ilişkisi var mı? Evetse, kalıtım kullanın. Değilse, kompozisyon kullanın.

Bir gemi "bir" yüzen makine ve bir yüzen makine "bir" makine. Yani, kalıtım onlar için gayet iyi. Ancak bir gemi elbette bir helikopter pisti değildir. Bu yüzden helikopter pistinin işlevselliğini daha iyi oluşturur.

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.