Saya menindaklanjuti pertanyaan ini , tetapi saya mengalihkan fokus saya dari kode ke prinsip.
Dari pemahaman saya tentang prinsip substitusi Liskov (LSP), metode apa pun yang ada di kelas dasar saya, mereka harus diimplementasikan dalam subkelas saya, dan menurut halaman ini , jika Anda mengganti metode di kelas dasar dan tidak melakukan apa pun atau melempar pengecualian, Anda melanggar prinsip.
Sekarang, masalah saya dapat diringkas seperti ini: Saya memiliki abstrak Weapon
class
, dan dua kelas, Sword
dan Reloadable
. Jika Reloadable
berisi spesifik method
, dipanggil Reload()
, saya harus downcast untuk mengaksesnya method
, dan, idealnya, Anda ingin menghindarinya.
Saya kemudian berpikir untuk menggunakan Strategy Pattern
. Dengan cara ini setiap senjata hanya menyadari tindakan yang mampu dilakukannya, jadi misalnya, Reloadable
senjata, jelas dapat memuat ulang, tetapi Sword
tidak bisa, dan bahkan tidak menyadari adanya Reload class/method
. Seperti yang saya nyatakan dalam posting Stack Overflow saya, saya tidak perlu downcast, dan saya bisa mengelola List<Weapon>
koleksi.
Di forum lain , jawaban pertama disarankan Sword
agar disadari Reload
, tapi jangan lakukan apa-apa. Jawaban yang sama diberikan pada halaman Stack Overflow yang saya tautkan di atas.
Saya tidak sepenuhnya mengerti mengapa. Mengapa melanggar prinsip dan membiarkan Pedang sadar Reload
, dan membiarkannya kosong? Seperti yang saya katakan di posting Stack Overflow saya, SP, cukup banyak memecahkan masalah saya.
Mengapa ini bukan solusi yang layak?
public final Weapon{
private final String name;
private final int damage;
private final List<AttackStrategy> validactions;
private final List<Actions> standardActions;
private Weapon(String name, int damage, List<AttackStrategy> standardActions, List<Actions> attacks)
{
this.name = name;
this.damage = damage;
standardActions = new ArrayList<Actions>(standardActions);
validAttacks = new ArrayList<AttackStrategy>(validActions);
}
public void standardAction(String action){} // -- Can call reload or aim here.
public int attack(String action){} // - Call any actions that are attacks.
public static Weapon Sword(String name, damage, List<AttackStrategy> standardActions, List<Actions> attacks){
return new Weapon(name, damage,standardActions, attacks) ;
}
}
Antarmuka dan Implementasi Serangan:
public interface AttackStrategy{
void attack(Enemy enemy);
}
public class Shoot implements AttackStrategy {
public void attack(Enemy enemy){
//code to shoot
}
}
public class Strike implements AttackStrategy {
public void attack(Enemy enemy){
//code to strike
}
}
reload()
mengosongkan atau standardActions
tidak mengandung tindakan reload hanya mekanisme yang berbeda. Tidak ada perbedaan mendasar. Anda bisa melakukan keduanya. => Solusi Anda adalah layak (yang pertanyaan Anda) .; Pedang tidak perlu tahu tentang memuat ulang jika Senjata berisi implementasi default kosong.
class Weapon { bool supportsReload(); void reload(); }
. Klien akan menguji jika didukung sebelum memuat ulang.reload
didefinisikan secara kontraktual untuk melempar iff!supportsReload()
. Itu mematuhi LSP iff drived kelas mematuhi protokol yang baru saja saya uraikan.