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
class
oraz dwie klasy Sword
i Reloadable
. Jeśli Reloadable
zawiera 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 Reloadable
broń może oczywiście przeładować, ale Sword
nie 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 Sword
być ś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 standardActions
też 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.reload
jest 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.