1

From my understanding a facade is a class with the sole purpose of simplifying the use of a specific system/module behavior (its methods). It should not contain any relevant logic of the underlying system, just centralize and simplify its use.

My questions is: how to create a facade (ie. simplify and centralize) of a system/module with events?

As far as I can understand it would make perfect sense to centralize the events of the system/module too. Hence all the user of that system has to do in order to understand how to use it is analyze its facade(s)'s interface(s). What I'm suggesting is something like the following (C#) code.

public class Facade
{
    // Fields

    public event EventHandler event1;
    public event EventHandler<string> event2;
    public event EventHandler event3;
    public event EventHandler<int> event4;
    // ...

    public Facade(SystemEventBus eventBus/*, underlying sub-systems references */)
    {
        // Subscribe to the sub-systems events, for instance using the system's event bus:
        eventBus.Subscribe<OnSomethingHappened>(OnSomethingHappened);
    }

    // Facade public methods

    // Internal Events Handling
    private void OnSomethingHappened()
    {
        event1?.Invoke(this, EventArgs.Empty);
    }
}

Although it feels odd to me, I can't argue against it. If we are already doing a facade with the purpose of centralizing and simplifying a system interface, it is logic to me that the events make part of that too. The goal should be the user being able to do everything related to using a system, solely through a facade.

Does that break any clean code rule? Is this even correct? Is there a better way to deal with the problem I described?

1 Answers1

1

Why Not.

Except I wouldn't have the facade responsible for managing the event handlers. Only responsible for forwarding the add/remove commands to the appropriate object in the backend.

internal class Backend
{
    public void register(EventHandler handler);
    public void deregister(EventHandler handler);
}

public class Facade
{
    private Backend _backend1;
    private Backend _backend2;

    public Facade(SystemEventBus eventBus/*, underlying sub-systems references */)
    {
        // Subscribe to the sub-systems events, for instance using the system's event bus:
        eventBus.Subscribe<OnSomethingHappened>(OnSomethingHappened);
    }

    // Facade public methods
    public void RegisterOnSomethingHappenned(EventHandler handler)
    {
        _backend1.Register(handler);
    }
    public void DeregisterOnSomethingHappenned(EventHandler handler)
    {
        _backend1.Deregister(handler);
    }
    public void RegisterOnSomethingElse(EventHandler handler)
    {
        _backend2.Register(handler);
    }
    public void DeregisterOnSomethingElse(EventHandler handler)
    {
        _backend2.DerRegister(handler);
    }

    //or even
    public void RegisterOnSomethingHappenned(EventHandler handler)
    {
        _backend1.Register(handler);
        _backend2.Register(handler);
    }
    public void DeregisterOnSomethingHappenned(EventHandler handler)
    {
        _backend1.Deregister(handler);
        _backend2.Deregister(handler);
    }
}

Kain0_0
  • 15,888
  • 16
  • 37
  • Cool, I think I prefer the additional events in the facade though; it makes things clearer in my opinion. Thanks for the answer. – andresantacruz Mar 09 '21 at 03:10
  • BTW forgot to ask: is there a reason behind why you prefer to do it the way you showed instead of creating new events? – andresantacruz Mar 09 '21 at 03:36
  • 1
    A facade's goal is to simplify interaction with a subsystem for a given purpose. Often facades are flyweight objects spun up as needed, in this light it makes sense to see them as specialist mechanics. They don't hold the machine inside themselves, they work on it and leave the machine behind to run. Need a mechanic, just call the facade back up. If you really want to reinterpret the events, you start pulling away from a facade and towards a stateful object. Here I would push that down into the underlying module to aggregate and reinterpret given events, expanding the ability of the engine. – Kain0_0 Mar 09 '21 at 03:57