1

Imagine I have an abstract class Node which has several methods and attributes. (Join a network, send a message, broadcast ...).

I want to be able to add/remove functionality to/from that Node class (Routing functionality, mining functionality, ...)

I was thinking about using a Decorator pattern since that let's me change the behaviour of that class dynamically on runtime.

return new RoutingNode(new BaseNode(name));

But now, I' starting to think that this is not the right choice since I'm using an abstract base class over an interface.

Basically I want to know if it's possible to add functionality to an existing object without subclassing the base class. For example, I want to add Routing functionality to let a node know he's able to route incoming requests or Mining functionality to let the node perform mining tasks. But this should be interoperatable meaning I can add add or remove functionality on runtime.

What would be the most elegant and best way to handle my use case scenario.

7
  • The decorator pattern doesn't care where you use an abstract class vs. an interface. The pattern is more-or-less programming language agnostic
    – Erik Eidt
    Commented Jan 20, 2018 at 2:41
  • 3
    By "add behavior" do you mean add new methods or change what they do when called? Commented Jan 20, 2018 at 4:06
  • I suspect 'add a new method' since a basic Node does not know about any routing or mining functionality so far.
    – Verhelst
    Commented Jan 20, 2018 at 8:25
  • 1
    @Verhelst if you're adding/remove functionality in runtime, how do you intend to access this functionality? It sounds like what you need is a dynamic list of behaviours (e.g. commands, as Vladislav Rastrusny mentions) which you can swap in and out, but we'd need more info about how you intend to interface with these behaviour to provide a focussed answer. Commented Jan 20, 2018 at 10:45
  • 1
    @Verhelst Well, you certainly can create a list of commands, add/remove them from internal object's list and invoke them via invoke($commandName, $params) method on your object. You can create a method to check if certain object has certain command like hasCommand($commandName), but this is something you should think twice about before you start implementing such things. Commented Jan 20, 2018 at 12:40

2 Answers 2

3

I am not aware of your complete plan, but I suspect, that what you are trying to do violates SRP.

One class should have only one responsibility. You can add a single functionality to your Node class via inheritance, but adding two kinds of functionality now violates SRP.

You can leave your Node as an object, that represents an actor and use, well, Commands for instance, to perform actions. I can't propose something good without having knowledge of your domain, but I think you got an idea.

1
  • To make myself more clear, I want to know if it's possible to add functionality to an existing object without subclassing the base class. For example, I want to add Routing functionality to let a node know he's able to route incoming requests or Mining functionality to let the node perform mining tasks. But this should be interoperatable meaning I can add add or remove functionality on runtime to a given node. I'm wondering if there's a good design pattern to handle this kind of situation.
    – Verhelst
    Commented Jan 20, 2018 at 9:29
1

Several times I've been facing the problem of having some kind of a graph (tree actually) and needed to do some operations with those nodes. In my case I wanted to split a 3D world into Quadtrees. But rendering was something else... I had to traverse the Quadtree nodes and do a rendering on it. Ie I split DATA and OPERATIONS which I suggest you should do.

On the other hand, there were times when I wanted to store some kind of metadata with my nodes depending on the OPERATIONS i wanted to do (performance reasons). So the solution was to be able to add some kind of custom Data to the nodes.

enum CustomDataType {SomeMiningData = 0, SomeRoutingData}
class ICustomData{
    virtual CustomDataType GetType() = 0;
}
class AdditionalDataContainer{
    void SetCustomData(ICustomData data);
    ICustomData GetCustomData(CustomDataType type);
}
class Node{
     AdditionalDataContainer additionalData;
}

Well the types and setters for custom data isn't important but you get the point.

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