Nesne yönelimli programlamanın en tartışmalı sorusu belki de şudur: Bir sınıfın başka bir sınıfın davranışını alması için kalıtım mı kullanılmalı, yoksa bileşim mi? Bu tartışma on yıllardır sürmekte; "composition over inheritance" (fonksiyon kompozisyonu vs kalıtım lehine) tavsiyesi artık neredeyse bir dil kuralı haline gelmiştir. Fonksiyon kompozisyonu vs kalıtım karşılaştırması soyutlama düzeyine kadar iner. Kalıtım, "A, B'nin bir türüdür" ilişkisini modeller. Kedi, Hayvan'ın bir türüdür; bu mantıkla Kedi, Hayvan sınıfından miras alır. İyi seçilmiş kalıtım hiyerarşisi okunabilir, anlaşılır ve tür sistemiyle uyumlu kod üretir. Sorun derinleştikçe ortaya çıkar. Gerçek dünya problemleri çoğu zaman tek boyutlu hiyerarşilere uymaz. Hem kaydedilen (Saveable) hem de ağdan yüklenen (Loadable) hem de kilitlenebilen (Lockable) bir nesneye ihtiyaç duyulduğunda, tek bir kalıtım zinciriyle bunu modellemek hızla zorlaşır. Java'daki arayüz çoğulluğu bu soruna kısmen yanıt verir; ancak arayüzler davranış taşımaz, yalnızca sözleşme tanımlar. Fonksiyon kompozisyonu vs kalıtım tartışmasında bileşimin güçlü yanı esnekliktir. Bir nesne, farklı sorumlulukları yerine getiren bağımsız bileşenleri barındırır. Bu bileşenler değiştirilebilir, test edilebilir ve yeniden kullanılabilir; üstelik aralarındaki bağımlılık çok daha zayıftır. Bir bileşimi değiştirmek, bir kalıtım hiyerarşisini kırmaktan çok daha az yan etki doğurur. Kalıtımın avantajı ise polimorfizm ve tip sistemi entegrasyonudur. Bir temel sınıf beklenen yerde türetilmiş sınıf geçirmek, tür güvenli ve okunabilir kod üretir. Dil düzeyindeki virtual dispatch mekanizması da doğrudan burada devreye girer. Pratik tavsiye: Sınıflar arasındaki ilişki gerçekten "bir türüdür" (is-a) ise ve hiyerarşi iki ya da üç katmanla sınırlı kalacaksa kalıtım makul seçimdir. Birden fazla soyut davranışın esnek biçimde birleştirilmesi gerekiyorsa fonksiyon kompozisyonu daha sürdürülebilir mimari sunar.