4

We know the Decorator design pattern, but how would someone go about implementing mutually exclusive decorators?

Let's say I have a decorator pattern to implement weapon modifiers in a game. The decorators would be, for example, "poisonous", "fire-enchanted", "ice-enchanted", etc. Now let's say I don't want my weapon to be both fire and ice-enchanted (just because), how would I go about implementing that logic in my decorator pattern?

Would I need to break it up or pervert it beyond recognition?

My best idea now is to have a GetDecorations() method on my interface and use it in the new decorator class to ensure that the new decoration won't violate any restrictions. But that seems to go against the Decorator principle of "not knowing" you can be decorated...

4

A decorator typically "wraps" a class and adds behavior in certain places.

If your example, perhaps there is a method that performs a calculation to get the damage a weapon deals. This would be more than a number, also returning a type, perhaps multiple: 10 physical damage, 2 cold damage.

I would have an interface for a weapon, that is implemented by actual weapons and your decorators. I would then have two sub-interfaces for the actual weapons and the decorators: a decorator cannot decorate another decorator because its constructor will not accept that type. In pseudocode:

class Damage {
  // state is multiple pairs of damage amounts and damage types.
}

interface Weapon {
  Damage getDamage();
}

interface RealWeapon : Weapon {}

interface WeaponDecorator : Weapon {}

class ColdEnchantment : WeaponDecorator {
  ColdEnchantment(RealWeapon w) { ... }
}

You can rely on the static type system in your language to prevent multiple decorators at compile-time.


Another method is having the enchantment be a field on the weapon:

interface Enchantment {
  // these are currently your decorators
}

interface Weapon [
  Damage getDamage();
  void setEnchantment(Enchantment e);
  void removeEnchantment();
}

Both methods are appropriate to different designs: I suggest considering them both in the big picture of your program and deciding which is a cleaner approach.

  • 2
    Worth noting that your second example is an instance of the strategy pattern. – Jules Feb 25 '16 at 18:17
  • Thanks, I understand from your example that I could easily limit it to a single decorator, but if I wanted to allow for example poisonous-firery weapons, then I can't really use the decorator... – dstj Feb 29 '16 at 22:23
  • @dstj ...which was the crux of your question to begin with. If you want to allow certain decorators to work together, you need a more intelligent (self-aware) solution than decorators to begin with. You need objects that actively check their applicability against each other, maybe (and I cringe typing this) a lightweight rules engine. – user22815 Feb 29 '16 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for?Browse other questions tagged or ask your own question.