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
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
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.
How about another interface. Maybe have various
Modifier
interfaces that the effects implement. These modifiers could do things like "increaseExplosivePower". You can doinstanceof
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.A common anti-pattern is using type checking, for example with
instanceof
, instead of polymorphism. Here's a simple example.Note that in the
draw()
method in classShape
, we determine what to draw by looking at the type of the current object, and then executing the appropriate code. This has several disadvantages: classShape
needs to know about all of its subclasses, and if you want to add a new shape, you'll have to modify classShape
too. It's much better to use polymorphism, by overriding thedraw()
method in the subclasses:This way, class
Shape
does not need to know about all of its subclasses, you don't need to modifyShape
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).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.