Estoy siguiendo esta pregunta , pero estoy cambiando mi enfoque del código a un principio.
Desde mi entendimiento del principio de sustitución de Liskov (LSP), cualquier método que esté en mi clase base, debe implementarse en mi subclase, y de acuerdo con esta página, si anula un método en la clase base y no hace nada o arroja un excepción, estás violando el principio.
Ahora, mi problema puede resumirse así: tengo un resumen Weapon
class
, y dos clases, Sword
y Reloadable
. Si Reloadable
contiene un específico method
, llamado Reload()
, tendría que bajar para acceder a eso method
, e idealmente, querrás evitarlo.
Entonces pensé en usar el Strategy Pattern
. De esta manera, cada arma solo era consciente de las acciones que es capaz de realizar, por lo que, por ejemplo, un Reloadable
arma, obviamente, puede recargarse, pero Sword
no puede, y ni siquiera es consciente de a Reload class/method
. Como dije en mi publicación de Stack Overflow, no tengo que abatir y puedo mantener una List<Weapon>
colección.
En otro foro , la primera respuesta sugerida Sword
para ser consciente Reload
, simplemente no haga nada. Esta misma respuesta se dio en la página de desbordamiento de pila a la que he vinculado anteriormente.
No entiendo completamente por qué. ¿Por qué violar el principio y permitir que Sword sea consciente Reload
y dejarlo en blanco? Como dije en mi publicación Stack Overflow, el SP resolvió mis problemas.
¿Por qué no es una solución 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) ;
}
}
Interfaz de ataque e implementación:
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()
blanco o si standardActions
no contiene una acción de recarga es solo un mecanismo diferente. No hay diferencia fundamental. Puedes hacer las dos cosas. => Su solución es viable (que era su pregunta) .; Sword no necesita saber sobre la recarga si Arma contiene una implementación predeterminada en blanco.
class Weapon { bool supportsReload(); void reload(); }
. Los clientes probarían si son compatibles antes de volver a cargar.reload
se define contractualmente para lanzar iff!supportsReload()
. Eso se adhiere al LSP si las clases derivadas se adhieren al protocolo que acabo de describir.