Je poursuis sur cette question , mais je passe mon attention du code à un principe.
D'après ma compréhension du principe de substitution de Liskov (LSP), quelles que soient les méthodes de ma classe de base, elles doivent être implémentées dans ma sous-classe, et selon cette page, si vous remplacez une méthode de la classe de base et qu'elle ne fait rien ou lance un exception, vous êtes en violation du principe.
Maintenant, mon problème peut être résumé comme ceci: j'ai un résumé Weapon
class
, et deux classes, Sword
et Reloadable
. Si Reloadable
contient un spécifique method
, appelé Reload()
, je devrais abattre pour y accéder method
, et, idéalement, vous voudriez éviter cela.
J'ai alors pensé à utiliser le Strategy Pattern
. De cette façon, chaque arme n'était consciente que des actions qu'elle est capable d'accomplir, donc par exemple, une Reloadable
arme peut évidemment se recharger, mais un Sword
ne peut pas, et n'est même pas au courant d'un Reload class/method
. Comme je l'ai indiqué dans mon article Stack Overflow, je n'ai pas à abattre et je peux maintenir une List<Weapon>
collection.
Sur un autre forum , la première réponse a suggéré de permettre Sword
d'être au courant Reload
, ne faites rien. Cette même réponse a été donnée sur la page Stack Overflow que j'ai liée à ci-dessus.
Je ne comprends pas vraiment pourquoi. Pourquoi violer le principe et permettre à Sword d'en être conscient Reload
et de le laisser vide? Comme je l'ai dit dans mon article sur Stack Overflow, le SP a à peu près résolu mes problèmes.
Pourquoi n'est-ce pas une solution viable?
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) ;
}
}
Interface d'attaque et implémentation:
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()
vide ou standardActions
ne contienne pas d'action de rechargement est juste un mécanisme différent. Il n'y a pas de différence fondamentale. Vous pouvez faire les deux. => Votre solution est viable (ce qui était votre question) .; Sword n'a pas besoin de connaître le rechargement si Weapon contient une implémentation par défaut vide.
class Weapon { bool supportsReload(); void reload(); }
. Les clients testeraient si pris en charge avant le rechargement.reload
est défini contractuellement pour lancer ssi!supportsReload()
. Cela adhère au LSP si les classes conduites ne respectent pas le protocole que je viens de décrire.