Benim bir temel sınıfım var Base. İki alt sınıfı var Sub1ve Sub2. Her alt sınıfın bazı ek yöntemleri vardır. Örneğin, Sub1yer alır Sandwich makeASandwich(Ingredients... ingredients), ve Sub2yer alır boolean contactAliens(Frequency onFrequency).
Bu yöntemler farklı parametreler alıp tamamen farklı şeyler yaptıkları için tamamen uyumsuzlar ve bu sorunu çözmek için sadece polimorfizm kullanamıyorum.
Baseİşlevlerin çoğunu sağlar ve geniş bir Basenesne koleksiyonuna sahibim . Ancak, tüm Basenesneler ya a Sub1ya da Sub2a'dır ve bazen onların ne olduğunu bilmem gerekir.
Aşağıdakileri yapmak kötü bir fikir gibi görünüyor:
for (Base base : bases) {
if (base instanceof Sub1) {
((Sub1) base).makeASandwich(getRandomIngredients());
// ... etc.
} else { // must be Sub2
((Sub2) base).contactAliens(getFrequency());
// ... etc.
}
}
Bu yüzden oyuncu seçmeden bunu önlemek için bir strateji ile geldi. Baseşimdi bu yöntemlere sahip:
boolean isSub1();
Sub1 asSub1();
Sub2 asSub2();
Ve tabii ki, Sub1bu yöntemleri uygular.
boolean isSub1() { return true; }
Sub1 asSub1(); { return this; }
Sub2 asSub2(); { throw new IllegalStateException(); }
Ve Sub2onları tam tersi şekilde uygular.
Ne yazık ki, şimdi Sub1ve Sub2bu yöntemleri kendi API'lerinde bulundurun. Böylece, örneğin bunu yapabilirim Sub1.
/** no need to use this if object is known to be Sub1 */
@Deprecated
boolean isSub1() { return true; }
/** no need to use this if object is known to be Sub1 */
@Deprecated
Sub1 asSub1(); { return this; }
/** no need to use this if object is known to be Sub1 */
@Deprecated
Sub2 asSub2(); { throw new IllegalStateException(); }
Bu şekilde, eğer nesne sadece a olarak bilinirse Base, bu yöntemler kullanımdan kaldırılmıştır ve alt sınıfın metotlarını çağırmak için kendisini farklı bir türe dökmek için kullanılabilir. Bu bana bir şekilde zarif görünüyor, ancak diğer taraftan, bir sınıftaki yöntemleri “kaldırmanın” bir yolu olarak kullanımdan kaldırılmış açıklamaları kötüye kullanıyorum.
Bir Sub1örnek gerçekten bir Temel olduğu için , kapsülleme yerine kalıtımı kullanmak mantıklıdır. İyi yaptığım şey mi? Bu sorunu çözmenin daha iyi bir yolu var mı?
instanceofçok fazla yazmaya ihtiyaç duyan bir şekilde hataya açık ve daha fazla alt sınıf eklemeyi zorlaştırıyorsunuz.
Sub1ve Sub2birbirlerinin yerine kullanılamazlar, o zaman neden bunları özel olarak muamele yapmak? Neden 'sandviç üreticileri' ve 'yabancı-temasçılar'ı ayrı ayrı takip etmiyorsunuz?