Avoid instanceof in a composite pattern

2020-07-14 05:28发布

I'm working on a project for university where we're programming a game. In this game several effects can occur and one effect can affect how another effect behaves. Now one of the idea's was using a composite pattern which seemed like a solid solution at first. The biggest problem here is that the way an effect behaves depends on what effect it's coupled with and the only way we saw to fix this was using .getClass() or instanceof which we want to avoid at all cost.

What are some ways to design this issue?

Edit (a small example): I don't have a explicit code example but I'll try to clarify a bit with the following example:

So the game has grenades (which can obviously explode and cause damage), this explosion is seen as an "ExplosionEffect". The square that the grenade is positioned on can have a powerfailure at runtime (PowerfailureEffect). The ExplosionEffect and PowerfailureEffect can be coupled and this causes the explosion to be stronger and cause more damage. The ExplosionEffect can also be coupled with other effects causing the explosion damage to behave even more differently

标签: java
4条回答
一夜七次
2楼-- · 2020-07-14 05:49
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();
}

I have a very simple suggestion. Why not make classes for each effect that implements an interface called Effect. Furthermore, if you are trying to simulate combination attacks, why not make functions for each of those combination attacks?

So in your example, it's going to be

public void combination2(PoisonEffect pe, PowerFailureEffect pf){

}

This might seems load of work, but I think this decouples your code very well and later you might find it easier to manage your code.

Please note that for the simplicity, they are not in separate class files =D.

查看更多
我想做一个坏孩纸
3楼-- · 2020-07-14 05:52

How about another interface. Maybe have various Modifier interfaces that the effects implement. These modifiers could do things like "increaseExplosivePower". You can do instanceof to see if the class implements the modifier and then one effect can modify the other.

Note: doing an instanceof on an interface is quite acceptable - you are not working out if it can do something based on what it is but on what APIs it has.

查看更多
乱世女痞
4楼-- · 2020-07-14 05:56

A common anti-pattern is using type checking, for example with instanceof, instead of polymorphism. Here's a simple example.

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 {
    // ...
}

Note that in the draw() method in class Shape, we determine what to draw by looking at the type of the current object, and then executing the appropriate code. This has several disadvantages: class Shape needs to know about all of its subclasses, and if you want to add a new shape, you'll have to modify class Shape too. It's much better to use polymorphism, by overriding the draw() method in the subclasses:

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
    }
}

This way, class Shape does not need to know about all of its subclasses, you don't need to modify Shape to add a new shape and all logic that belongs to a particular shape is in the place where it belongs (the class for that shape).

查看更多
Melony?
5楼-- · 2020-07-14 05:58

You could use the Visitor Design Pattern. All effect class implements an Effect interface. Main class ask the EffectB class using the Effect interface method how it should behave. Implementation of Effect's method in EffectB class call the right method in main class.

查看更多
登录 后发表回答