Kontynuuję to pytanie , ale skupiam się z kodu na zasadzie.
Z mojego zrozumienia zasady podstawienia Liskowa (LSP), wszystkie metody w mojej klasie bazowej muszą być zaimplementowane w mojej podklasie i zgodnie z tą stroną, jeśli zastąpisz metodę w klasie bazowej i nie robi ona nic ani nie rzuca wyjątek, naruszasz zasadę.
Teraz mój problem można podsumować w następujący sposób: mam streszczenie Weapon classoraz dwie klasy Swordi Reloadable. Jeśli Reloadablezawiera konkretny method, zwany Reload(), musiałbym zejść na dół, aby uzyskać do niego dostęp method, i najlepiej byłoby tego uniknąć.
Potem pomyślałem o użyciu Strategy Pattern. W ten sposób każda broń była świadoma działań, które może wykonać, więc na przykład Reloadablebroń może oczywiście przeładować, ale Swordnie może, a nawet nie jest świadoma Reload class/method. Jak stwierdziłem w moim wpisie Przepełnienie stosu, nie muszę spuszczać i mogę zachować List<Weapon>kolekcję.
Na innym forum pierwsza odpowiedź sugerowała , że możesz Swordbyć świadomy Reload, po prostu nic nie rób. Ta sama odpowiedź została podana na stronie Przepełnienie stosu, do której odsyłam powyżej.
Nie do końca rozumiem dlaczego. Po co naruszać tę zasadę i pozwolić, by Miecz był tego świadomy Reload, i pozostawić to puste? Jak powiedziałem w moim wpisie Przepełnienie stosu, SP prawie rozwiązało moje problemy.
Dlaczego nie jest to realne rozwiązanie?
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) ;
}
}
Interfejs ataku i implementacja:
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()puste pole, czy standardActionsteż nie zawiera operacji przeładowania, to po prostu inny mechanizm. Nie ma zasadniczej różnicy. Możesz zrobić jedno i drugie. => Twoje rozwiązanie jest realne (jakie było twoje pytanie) .; Miecz nie musi wiedzieć o przeładowaniu, jeśli Broń zawiera pustą domyślną implementację.
class Weapon { bool supportsReload(); void reload(); }. Klienci sprawdziliby, czy są obsługiwani przed ponownym załadowaniem.reloadjest określona w umowie, aby rzucić IFF!supportsReload(). Przestrzeganie klas kierowanych przez LSP iff jest zgodne z protokołem, który właśnie przedstawiłem.