1

Imagine a simple Controller (as in process control) interface. I have some concrete classes, say PIDController, that implement it. I also have some decorator classes that extend these classes somehow, say ITAETuningDecorator.

Now imagine that a FloodGate class has a private Controller field. I would like, from the outside and at runtime, to attach to the Controller in FloodGate an ITAETuningDecorator. How can I do it? I have no access to the field from the outside and obviously the decorator needs a reference to the original controller to be built.

5
  • 1
    Could you add a FloodGate.DecorateController(ControllerDecoratorFactory factory) method which would do something like { this.controller = factory.Create(this.controller); } ?
    – MetaFight
    Sep 1, 2014 at 10:36
  • Oh actually that's a pretty neat idea. So basically I just pass to the floodgate a function controller-->decoratedController and let it deal with it, correct?
    – CarrKnight
    Sep 1, 2014 at 11:11
  • Can you elaborate on what you mean by "attach a Decorator" ? Do you want the decorated version to stick in the FloodGate permanently or wouldn't you be just fine with an ephemeral decorated Controller ? Sep 1, 2014 at 11:33
  • I'd like the private field in FloodGate to point to the decorator rather than the concrete class being decorated. I suppose that's your definition of stick permanently, right? Anyway @MetaFight, your solution works just fine. If you write it in an answer I'll choose it as best answer and be done with it.
    – CarrKnight
    Sep 1, 2014 at 11:38
  • 1
    Yes that's what I meant, but why would you do that ? It's pretty rare to have to replace an existing instance of something with a subclass of it at runtime, that's why I'm asking. It might be legitimate in some cases, but might be a design smell as well. Sep 1, 2014 at 11:42

2 Answers 2

3

The question is: Who instantiates the Controller?

  • If it's created outside the FloodGate instance, you can wrap it there and pass the wrapped instance into the FloodGate.
  • If it's created by the FloodGate internally (which seems strange to me, but I'm not into your domain), you could either change that and pass it in (e.g. as a constructor parameter) or add a method addControllerDecorator(Controller c) to the FloodGate. The latter implies that you can instantiate the wrapper and later set the instance it wraps, which looks like a poor design choice to me...
5
  • Thank you for your answer! My real problem is not so much at instantiation. I'd like to decorate my Controller long after it has been instantiated and has been used for a while.
    – CarrKnight
    Sep 1, 2014 at 7:38
  • Ok, but you need to keep the same FloodGate instance? Then you could do something like floodGate.setController(new Wrapper(floodGate.getController())) to add the wrapper. Alternatively, you create a new FloodGate and pass it the wrapped controller from the old gate.
    – Sven Amann
    Sep 1, 2014 at 8:55
  • @CarrKnight: So you want to effectively replace the Controller used by a Floodgate? Sep 1, 2014 at 9:11
  • @BartvanIngenSchenau not really. The underlying controller has to stay. I just want to attach a decorator to it to adjust its behavior on a need basis, but I don't want to lose the state of the original concrete Controller. I am afraid i will have to use getter/setter which is annoying because I really don't want to let any reference to the private field out. Sure beats cloning the floodgate everytime.
    – CarrKnight
    Sep 1, 2014 at 11:09
  • @CarrKnight: How about this scheme: Floodgate has references to two controllers, a bare bones one and a decorated version, and provides methods to switch between them. Optionally, the Floodgate can even be unaware that the two controllers are related and only the instantiating logic dictates that a Floodgate gets a Controller and a decorator wrapped around that same Controller. Sep 1, 2014 at 12:28
0

The "outside world" code could use reflection (the nasty kind) to access and / or update the private field.

But a better idea (IMO) would modify your APIs to provide access to the fields that you want to decorate. This could take the form of a getters and / or setters, or it could be more specialized methods that add and (if necessary) remove the decorations. In short "decoratibility" should be part of the API.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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