避免复合模式中的instanceof

我正在为大学做一个项目,我们正在为游戏编程。 在这个游戏中可以发生几种效果,一种效果可以影响另一种效果的行为。 现在,其中一个想法是使用复合图案,起初看起来像是一个坚固的解决方案。 这里最大的问题是效果的行为方式取决于它与之结合的效果,我们看到解决这个问题的唯一方法是使用我们想要不惜一切代价避免使用的.getClass()或instanceof。

有哪些方法可以设计这个问题?

编辑(一个小例子):我没有明确的代码示例,但我将尝试用以下示例澄清一下:

因此游戏中有手榴弹(显然会爆炸并造成伤害),这种爆炸被视为“爆炸效应”。 手榴弹所在的方形在运行时可能会出现电力故障(PowerfailureEffect)。 ExplosionEffect和PowerfailureEffect可以耦合,这会导致爆炸更强烈并造成更多伤害。 ExplosionEffect还可以与其他效果相结合,导致爆炸伤害的行为更加不同

您可以使用访客设计模式。 所有效果类都实现了一个Effect接口。 主类使用Effect接口方法询问EffectB类应该如何表现。 EffectB类中Effect的方法的实现在主类中调用正确的方法。

另一个界面怎么样 也许有效果实现的各种Modifier接口。 这些修饰符可以执行“increaseExplosivePower”之类的操作。 您可以执行instanceof来查看该类是否实现了修饰符,然后一个效果可以修改另一个。

注意:在接口上执行instanceof是完全可以接受的 – 如果它可以基于它的内容而不是它所具有的API来执行某些操作,那么您就无法解决这个问题。

 public void test(){ methodForWaterEffect(new WaterEffect()); combinationAttack1(new FireEffect(), new WaterEffect()); } interface Effect{ public void activateEffect(); } class FireEffect implements Effect{ @Override public void activateEffect() { System.out.println("Fire!"); } } class WaterEffect implements Effect{ @Override public void activateEffect() { System.out.println("Water!"); } } public void combinationAttack1(FireEffect fe, WaterEffect we){ //your algorithm here } public void methodForWaterEffect(WaterEffect fe){ fe.activateEffect(); } 

我有一个非常简单的建议。 为什么不为实现名为Effect的接口的每个效果创建类。 此外,如果您正在尝试模拟组合攻击,为什么不为每个组合攻击制作函数?

所以在你的例子中,它将是

 public void combination2(PoisonEffect pe, PowerFailureEffect pf){ } 

这可能看起来很重要,但我认为这会很好地解耦您的代码,以后您可能会发现管理代码更容易。

请注意,为简单起见,它们不在单独的类文件中= D.

常见的反模式是使用类型检查,例如使用instanceof ,而不是多态。 这是一个简单的例子。

 public class Shape { public void draw() { if (this instanceof Square) { // Draw a square } else if (this instanceof Circle) { // Draw a circle } } } public class Square extends Shape { // ... } public class Circle extends Shape { // ... } 

请注意,在Shape类的draw()方法中,我们通过查看当前对象的类型,然后执行适当的代码来确定要绘制的内容。 这有几个缺点:类Shape需要知道它的所有子类,如果你想添加一个新形状,你也必须修改类Shape 。 通过覆盖子类中的draw()方法,使用多态更好:

 public abstract class Shape { public abstract void draw(); } public class Square extends Shape { public void draw() { // Draw a square } } public class Circle extends Shape { public void draw() { // Draw a circle } } 

这样,类Shape不需要知道它的所有子类,你不需要修改Shape来添加一个新的形状,属于特定形状的所有逻辑都在它所属的位置(该类的类)形状)。