我正在跟进这个问题,但是我将重点从代码转换为原则。
根据我对Liskov替换原理(LSP)的理解,无论我的基类中有什么方法,它们都必须在我的子类中实现,并且根据此页面,如果您在基类中重写了一个方法,则它什么也不做或抛出一个错误。例外,您违反了该原则。
现在,我的问题可以这样总结:我有一个abstract Weapon
class
,两个类,Sword
和Reloadable
。如果Reloadable
包含一个特定的method
,称为Reload()
,我将不得不向下访问以访问该method
,并且理想情况下,您希望避免这种情况。
然后,我想到了使用Strategy Pattern
。这样,每把武器都只知道它能够执行的动作,因此,例如,一种Reloadable
武器显然可以重新装弹,但是Sword
不能,甚至不知道Reload class/method
。正如我在Stack Overflow帖子中所说的那样,我不必沮丧,也可以维护List<Weapon>
收藏集。
在另一个论坛上,第一个答案建议让其Sword
意识到Reload
,只是什么也不要做。我在上面链接到的“堆栈溢出”页面上也给出了相同的答案。
我不完全明白为什么。为什么要违反该原则并让Sword知道Reload
并保留为空?正如我在Stack Overflow帖子中所说,SP几乎解决了我的问题。
为什么它不是可行的解决方案?
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) ;
}
}
攻击接口和实现:
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()
空白或standardActions
不包含重新加载操作只是一种不同的机制。没有根本的区别。两者都可以。=>您的解决方案是可行的(这是您的问题)。如果Weapon包含空白的默认实现,Sword不需要了解有关重新加载的信息。
class Weapon { bool supportsReload(); void reload(); }
。客户端将在重新加载之前测试是否受支持。reload
根据合同定义抛出iff!supportsReload()
。如果驱动类遵循我刚刚概述的协议,则遵循LSP。