Mediator, Facade and Adapter cooperation

Image credit: Pexels

Mediator, Facade and Adapter cooperation

Emilia Szymańska bio photo By Emilia Szymańska Comment

Hi guys! I spent last several days on designing the architecture of my master thesis project. I have to admit - it feels nice being able to enforce some nice and clean structure after several months of JS programming… I also started digging into some of my new IT books and I found three architectural patterns that will be really useful in my case.

The Mediator pattern

This pattern is really useful when there are different beings that should react to each other actions, but are not meant to be tightly coupled. Mediator helps to reduce communication complexity between these objects by enforcing its own politics in a transparent way. As a result we get a nice aggregation of the workflow knowledge, what makes it easier to understand and maintain.

In my project the GameStateManager object will act as a mediator. It will get information about the state changes, invoke the logical engine methods to compute a new state and then propagate it among the entity objects. An entity object will only care about getting its new state and reacting to it – but that reaction will not involve changing the state of another object directly – that can be done only by the GameStateManager that only retrieves the results computed by the engine.

That is really important, since this is the core concept of my whole work – all interactions between objects are defined in logical rules.

The Facade pattern

The class (called LogicOperations in my project) that represents the usage of this pattern is my biggest concern right now. I have a dll library full of strange-looking, non – compatible code that only pretends to be written in C #. It has its own generic types and extension methods that are similar to the ones we all know and love, but are still not eager to socialize and adapt. Since it is a whole temporal logic library written as a PhD project by one of my friends, it also contains many complex functions that are not needed in my project.

I really didn’t want to clutter my classes with this strange, converted code (it has gone through conversions Scala -> Java -> C# …) so the first thing I started to work on was a class that will hide all of the complexity of this module and will only present the most needed methods. It doesn’t introduce any new logic or behavior – it only simplifies access to the temporal engine. It doesn’t even convert types from Scala world to my engine’s representation (for example my State of the game is a converted Set object), because that would be introducing some external behavior. This is where an adapter leaps into action.

public static class LogicOperations
{
    public static Graph GetHistoryGraph(string rules)
    {
        var expr = (Types.Expr)Parser.parse(rules).get();
        return LncInferenceEngine.getHistoryGraph(expr);
    }

    public static bool PathExists(Graph graph, Set from, Set to)
    {
        return (graph as HistoryGraph).findPath(from, to) != null;
    }

    public static Set GetSuccessors(Graph graph, Set point)
    {
        return graph.getSuccessors(point);
    } 

    public static Set NodeFromString(string expression)
    {
        var set = DnfConverter.convert((Types.Expr)Parser.parse(expression).get());
        return (Set)(set as IterableLike).head();
    }

    public static List FindPath(Graph graph, Set from, Set to)
    {
        return graph.findPath(from, to);
    } 
}

See? There is even a List class that behaves in a totally different way than the System.Collection.Generic one… ;_;

The Adapter pattern

This pattern translates an interface for an object or class into an interface compatible with a specific system. That is exactly what my LogicEngine class responsibility is. The objects that are used by the LogicOperations module are totally incompatible with my whole project – these are some specific types from the Scala language that got converted to C# in a really strange way. The adapter helps to minimize the number of places where that strange code is being used. It translates results of operations on temporal logic to the components used by my engine.

At a first glance these patterns all looks similar, but as you can see, in my project the difference can be clearly distinguished. The resources that helped me with finding this distinction where these books:

Learning JavaScript Design Patterns by Addy Osmani - it contains JavaScript in the title but it is a really great guide through the patterns world and it’s free,

Agile Software Development, Principles, Patterns, and Practices by Robert C. Martin – not free, but totally worth it’s price.

As always – if you find this post helpful and would like to get notified when future ones appear, like my fan page or follow me on Twitter. (。◕‿◕。)

comments powered by Disqus