Question

I recently came to a solution which I particularly like and I would like to know if it has a name as a design pattern or whether it can be considered as matching the State pattern. The problem this solution solves is the following (I will use Java as language for the examples):

We have a system that boots and we need different output levels depending on what subsystems have already been initialized.

(WARNING! This is just an example, NOT working code)

Lets say we have: ConsoleTextMsgs, NetworkMsgs and GUIMsgs i/o subsystems represented as homonymous classes. We have also a class named 'System' implementing the booting system.

interface IOSubsystem {
    void showMessage(String msg);
}

class ConsoleTextMsgs implements IOSubsystem
{
    public ConsoleTextMsgs() { ... };

    void showMessage(String msg) {
        impPrint((new Date()).toString() + "\t:\t" + msg);
    }

    private impPrint(String msg) { ... };

}

//`ConsoleTextMsgs`, `NetworkMsgs` and  `GUIMsgs`
class NetworkMsgs implements IOSubsystem
{
    public NetworkMsgs(IOSubsystem decorated, NetworkService serv)
    {
        this.decorated = decorated;
        ...
        ...
    }

    void showMessage(String msg) {
        send2net((new Date()).toString() + "\t:\t" + msg); //New functionality which uses the NetworkService
        decorated.showMessage(msg); //I want the message to by shown at the console too.
    }

    private send2net(String msg) { ... };

    IOSubsystem decorated;
}

//`ConsoleTextMsgs`, `NetworkMsgs` and  `GUIMsgs`
class GUIMsgs implements IOSubsystem
{
    public GUIMsgs(IOSubsystem decorated, GUIService serv)
    {
        this.decorated = decorated;
        ...
        ...
    }

    void showMessage(String msg) {
        showOnGUI((new Date()).toString() + "\t:\t" + msg); //New functionality which uses the GUIService
        decorated.showMessage(msg); //I want the message to by shown at the console too.
    }

    private showOnGUI(String msg) { ... };

    IOSubsystem decorated;
}

NetworkMsgs can't be used until a NetworkService is available and booted as well as GUIMsgs can't be used until the GUIService is ready.

As you can see, it is an incremental output system since whenever I emit the message through the network I want to show it at the console and whenever showing a GUI message I want it to be sent to the network and shown at the console.

However, these systems aren't available at the same time: Console will be available from the beginning whereas NetworkService will take a little longer to be ready and GUIService will be the last to be prepared.

So I have a booting process given by the 'boot' method at 'System' class:

class System
{
    public System()
    {
    ...
        output = new ConsoleTextMsgs();
    ...
    }

    void boot()
    {
        output.showMessage("Starting system");
        ...
        output.showMessage("Doing some stuff");
        ...
        output.showMessage("Starting network service");
        NetworkService nsrv = bootNetwork();

        output = new NetworkMsgs(output, nsrv );  // I call it hot swap decoration, how do you call it?

        ...
        ...
        ... 

        GUIService gsrv = bootGUI();

        output = new GUIMsgs(output,gsrv); // Here we are again, does this even have a name?

    }    
    private IOSubsystem output;
}

I think it can be seen as State+Decorator pattern. Many people may be using it and I would like to know if it has a label.

Was it helpful?

Solution

This can certainly work, and it's clearly using a Decorator pattern. And it resembles State somewhat, but in a pretty simple way and not really using some of the features of the pattern.

I don't know of a name for this.

I'd personally be more inclined to use a Composite here, and implement the various other versions of the IOSubsystem without decorating.

If you define your composite with something like:

public class CompositeIOSubsystem implements IOSubsystem {

    List<IOSubsystem> subsystems = new ArrayList<IOSubsystem>();

    public void showMessage(String msg) {
        for (IOSubsystem subsystem: subsystems)
            subsystem.showMessage(msg);
    }

    public void add(IOSubsystem subsystem) {
        subsystems.add(subsystem);
    }
}

then you don't have to actually "hot-swap" anything, and all the delegation is handled in one place. Simply put an empty composite in place at the start of your boot and add the subsystems to the composite as they become available.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top