GoF – Abstract Factory Pattern

What a wild summer it has been. With everything going on in the world, it’s important to take a moment to reflect on what’s going well, right now. With non-essential travel on pause, I haven’t needed to travel for work. Which means I’ve had more time to enjoy the summer with family, and more time to code and dream up blog posts. I think COVID has also had some positive impacts on society, I’ve definitely noticed a focus on hygiene in public these days, and that is wonderful.

In my reflection, I was recalling earlier this year when I read the famous Gang of Four book “Design Patterns : Elements of Reusable Object Oriented Software” – Gamma, Johnson, Vlissides, Helm. If you’ve not heard of this book, it’s basically considered the bible when it comes to Design Patterns in Software. This was the first time I had read the book. Yes — I developed software professionally for this long, and had never read this book. It was about time. I could basically feel the snickers and sneers as I walked the isles of my local grocery store. “You’ve not read Design Patterns by GoF?” “What kind of software developer are you?” Now, in reality this was just my chronic case of impostor syndrome creeping up my spine. Even though I had read countless articles on design patterns, and dove Head First into a myriad of them when I read “Head First Design Patterns“. It still didn’t measure up, I hadn’t read the real thing. So in January, I did it. I bought the e-book, and I read it. I wouldn’t say it was a cover to cover read. Like I said, it wasn’t my first pattern rodeo. A lot of the patterns, I had learned about, seen, or even implemented before. So it was more of a refresher than anything else. The book is well written, though a bit dated. What I found nice was that the examples were in C++. Anyways, this isn’t a review on the book. It was just something that came and went, back in January. Then during the COVID pandemic, I’ve been scratching my head for blog post ideas. I wish I possessed the type_traits that some of these other bloggers possess to seemingly pull insightful ideas out of their brains, and write delicate and succinct posts packed with code and useful information. I felt that I should go back to basics, and do a post or two on the cult classic GoF Design Pattern book, update it with modern C++, and put my own Peter spin on the patterns.

“You’re losing our attention; we don’t want to hear about your life. Get on with the post.” — Reddit

Call it what you want to call it. Kismet, fate, alphabetical sorting, the first design pattern in the book. I landed on the Abstract Factory pattern. If you’re unfamiliar with the pattern the definition is to “provide an interface for creating families of related objects without specifying their concrete classes”. What this means, is that the Abstract Factory, is an interface to an object that will create a bunch of objects, and hand them off as interfaces. I’ve taken the liberty to copy the UML from the book.

As you can see from the UML, the Abstract Factory is used by clients to put an opaque layer, or interface between the actual implementation, and the caller. As we all know, this is done through a programming paradigm called polymorphism. The factory is abstract to our client, as well as the objects that it is creating. So, the abstract factory, creates a family of abstract objects that the client can work with. The canonical example of this would be a windowing system, whereby you can have different display systems, that all expose the same family of objects. Consider Linux and Windows windowing systems, they all have windows, button controls, scrollbars, etc. So when working with a windowing system, it could make sense to apply the Abstract Factory Pattern.

I’ll use the original GoF example as my starting point. Though, I’m going to apply modern C++ to it, so it won’t be line for line the same as the example in the book. As well, I won’t detail the map components Maze, Wall, Room, Door, as I don’t feel their necessary to illustrate the point.

class AbstractMazeFactory
{
public
    virtual ~MazeFactory() = default;
    virtual std::unique_ptr<Maze> MakeMaze() =0;
    virtual std::unique_ptr<Wall> MakeWall() =0;
    virtual std::unique_ptr<Room> MakeRoom(int room) =0;
    virtual std::unique_ptr<Door> MakeDoor(Room &r1, Room &r2) = 0;
};

std::unique_ptr<Maze> CreateMaze(AbstractMazeFactory &factory)
{
    auto maze = factory.MakeMaze();
    auto room1 = factory.MakeRoom(1);
    auto room2 = factory.MakeRoom(2);
    auto door = factory.MakeDoor(*room1, *room2);

    room1->SetSide(North, factory->MakeWall());
    room1->SetSide(East, door);
    room1->SetSide(South, factory->MakeWall());
    room1->SetSide(West, factory->MakeWall());

    maze->AddRoom(room1);

    room2->SetSide(North, factory->MakeWall());
    room2->SetSide(East, factory->MakeWall());
    room2->SetSide(South, factory->MakeWall());
    room2->SetSide(West, door);

    maze->AddRoom(room2);

    return maze;
}

We’ve separated the logic of creating the maze from the construction of the maze components, as well as their actual implementation. To take advantage, you just need to implement concrete components, and derive from the AbstractFactory which will return these components.

class EnchantedMaze : public Maze { ... };
class EnchantedWall : public Wall { ... };
class EnchantedDoor : public Door { ... };
class EnchantedRoom : public Room { ... };

class MazeFactory : public AbstractMazeFactory { ... };

class EnchantedMazeFactory : public MazeFactory
{
public:

    virtual std::unique_ptr<Room> MakeRoom(int room) override
    {
         return std::make_unique<EnchantedRoom>(room, CastSpell());
    }
    
   virtual std::unique_ptr<Door> MakeDoor(Room &r1, Room &r2) override
   {
         return std::make_unique<DoorNeedingSpell>(r1, r2);
   }

private:
    Spell* CastSpell();
};

This decoupling enables you to change the implementation of your components, without having to disrupt the creation algorithm. If you’re worried about compiling, when you modify your components it’s not necessary to recompile CreateMaze.

The book outlines the following benefits and liabilities

  1. It isolates concrete classes. The pattern funnels creation through a single interface. Which ensures a single point in which your application must create objects. Because the application must interact with both the factory, and its components via their interfaces details of their implementation remain opaque to the outside algorithms.
  2. It makes exchanging product families easy. Because a client interacts through a single interface, it makes changing this interface as easy as an assignment to a new factory. However, each factory must supply entire product family as a whole.
  3. It promotes consistency among products. Because the factory dictates creation of a group of related items, which will likely be codependent. Since it forces a single source for creation, it makes enforcing this easy.
  4. Supporting new products is difficult. Although changing the factory is easy, creating a new product family is often not. It means defining and implementing a new factory, as well as the entire product set.

You can start to smell when this pattern is helpful, if you’re starting to invent creative ways to change implementation of sets of components within your system. Or, if you’re starting to mix the structure of your application, with component implementation details.

The problem with this GoF patterns is that it results in a lot of boilerplate code. If we look at the AFP (Abstract Factory Pattern), you have to create the factory interface. Then for each family of products you have to implement the concrete classes. This type of repetition tends to get worked around in clever fashions, which can often become unmaintainable nightmares.

My intention with this post (series of posts?) was to make a library that makes using the GoF patterns accessible, and reduces the amount of boilerplate needed. As well as modernizing the solutions, and being creative where I could. It’s hard to top something that’s lasted the test of time like this. I also wanted to make the library easy to use, hard to use wrong, and to illustrate the use of the intended pattern.

When we boil down the Abstract Factory, we have two major components. We have the factory itself, and the family of components. The factory is a set of methods that create, and return each component objects. Which means that for N components in a family, you’ll have N factory functions in the factory. This was my first thought was to remove that boilerplate cost. But how? Well, if we ask ourselves the question of what each factory function is, it’s specifying the type to create at compile time. In C++ we have a neat tool for generalizing functions based on type at compile time. It’s called template programming. So we can start there, let’s look at a simple widget factory example. How would we want to use it.

void create_screen(abstract_widget_factory &factory)
{
    auto w = factory.create<window>(); 
    auto b = factory.create<Button>();
    
    b->set_text("Hello World");
    w->add_widget(b);

   w->show();
};

My initial thought was to do something with template specialization, but the wall that I kept running into is that the Abstract Factory pattern makes heavy use of runtime polymorphism. The template system is compile-time. What does this mean? In the example CreateScreen above, the actual concrete type of the factory, doesn’t need to be known past that it is an AbstractWidgetFactory, and through the miracle of virtual function dispatching, it will land in the appropriate function for the concrete class when the call is dispatched. Template functions are similar, in that they allow you to apply a function to an interface (read concept), but the actual type must be specified at compile time. The reason for this, to vastly simplify it, implements the template function for the given type, instead of you having to write it yourself. Because of this, when you’re trying to replace boilerplate, using the template system typically comes in handy. In order to implement the function above, you would need to define the AbstractWidgetFactory along the lines of

class abstract_widget_factory
{
public:
   virtual ~abstract_widget_factory() = default;

   template <typename T>
   virtual std::unique_ptr<T> create() = 0;
};

This isn’t valid C++, and it makes sense as to why. Because in order to have the pure virtual function (=0), the inherited class must implement the function. But the function is a template, it can be any number of different instantiations of the function. Therefore, what does the concrete class actually implement? Thus, this is no-bueno.

Given that we know the set of objects we’re creating, I thought I may be able to solve this with a concept. However, I came to the conclusion that this would just push the boilerplate code I was trying to avoid with the runtime interface, I would have to write with the concept. I’ll admit my level of comfortably with concepts is quite low, and I only conceptualized the idea. I didn’t actually try and implement it. If you have an idea of how to tackle this with concepts, I am all ears!

So where does this leave us? How can we combine runtime decisions, with compile-time decisions? What does that even mean, or look like? First, what are the runtime decisions we’re trying to make, and what are the compile time decisions? The compile time decision, is the choice of the abstract component we want to use, in this case Button, or Window. In the GoF example, Maze, Wall, Room, etc… The runtime choice is the actual factory class, which by nature of the pattern, should dictate the implementations of the components.

In my research, I found a Dr. Dobb’s (RIP) article from 2001, by Herb Sutter and Jim Hyslop. the article is written in story form, which makes it a pretty fun read. The best part, the story was actually exactly the problem I was trying to solve. I was still trying to solve the problem on my own, so I avoided reading the article in-depth until after I had a working model. Though, I did use it to gut check that my idea that a registry for creation was a track I wanted to go on. So I landed on this.

class abstract_factory
{
public:
     template <typename BaseT>
     std::unique_ptr<BaseT> create()
     {
          // semi-pseudo code
          auto creator = creators_[BaseT::type_id()];
          // something like creator->create<...>();
          // return it.
     }

protected:
    template <typename BaseT, typename DerivedT>
    void map()
    {
        // creators_[BaseT::type_id()] = I need something here;
    }

private:
    std::map<const char*, creator?> creators_;

};

Then, a client could use the factory something like this.

class linux_widget_factory : public abstract_factory
{
public:
     linux_widget_factory()
     {
          map<button, linux_button>();
          map<window, linux_window>();
     }
};

void create_screen(abstract_factory &factory)
{
    auto w = factory.create<window>(); 
    auto b = factory.create<button>();
    
    b->set_text("Hello World");
    w->add_widget(b);

   w->show();
}

int main()
{
    linux_widget_factory f;
    create_screen(f);
}

Future Peter here: One of the problems that the Dr.Dobb’s article suffered from, was that the singleton factory was on a per-hierarchy basis. In that, you could only create one base type, with multiple derived types. As well, being a singleton doesn’t allow for different factories for different families of components.

This implementation looks pretty good, and it works like the GoF Abstract Factory. You’re able to hide the implementation of a family of objects, behind one class which forces the client to go through its interface. It’s just how do we make this work? What we’re really trying to do, is to package up the creation into a function that can be called. When we package it up, we want to hide away any type specific information because this will allow for type generalization, and then when we call the creation we want to as if by a miracle re-hydrate the type for the object we’re creating. There’s a technique for what we’re trying to do. You might know what I’m talking about from some of my previous articles, or you’re just familiar with it. It’s called type erasure. Like the Sutter / Hyslop factory, we’ll make our factory creation function work on a base type. The most base type, void. Then through the miracle of templates, we’ll reassign the type when the client calls create.

If you’re unfamiliar with type erasure, I’ll give a quick overview, and leave a couple of references to articles I’ve read in the past at the bottom.

Basically, any kind of runtime polymorphism is a form of type erasure, you’re hiding away the concrete type to work with a more generic type. Typically when we refer to type erasure in C++, we mean hiding all the type information away. Since we want to work with all types, we’ll have to remove any type information.

Disclaimer: Don’t try what you’re about to see at work. Using type erasure in this way removes the type safety provided by the compiler.

// We want to hide the creation behind some interface.
class creator_base
{
public:
    virtual ~creator_base() = default;
    virtual void *create() = 0;
};

Now, we’ve turned creation of our objects upside down, and hid it behind a very generic interface. When we call create, we’ll get back a void pointer, that’s all a void pointer. Unbeknownst to the compiler it’s actually our concrete object, we’ve just effectively turned off type safety for this call.

The next part of type erasure is to embed the actual type behind the interface. In our case, it looks something like this.

template <typename T>
class creator : public creator_base
{
public:
   virtual void* create() override final
   {
        auto t = std::make_unique<T>();
        return t.release();
   }
};

Easy — so now creator<linux_button> will create a linux_button, and return the opaque void handle to it. Now all that’s left when we’re creating is to flip the object over to the base type we want.

class abstract_factory
{
public:
     template <typename BaseT>
     std::unique_ptr<BaseT> create()
     {
          // semi-pseudo code
          auto creator = creators_[BaseT::type_id()];
          void *obj = creator->create();
          return std::unique_ptr<BaseT>(obj);
     }

protected:
    template <typename BaseT, typename DerivedT>
    void map()
    {
        creators_[BaseT::type_id()] = std::make_unique<creator<DerivedT>>();
    }

private:
    std::map<const char*, std::unique_ptr<creator_base>> creators_;

};

The last piece of this puzzle is the BaseT::type_id(). What I did in my first iteration, was to just stamp this on to my base product classes like this. This is changed to a different pattern in the actual implementation.

class button
{
public:
   static constexpr const char* type_id() { return "button"; }
public:
   virtual ~button() = default;
   virtual void click() =0; 
   virtual void set_text(const std::string &text) =0;
};

My original goal was to reduce the boilerplate of the original GoF pattern. Which, I did. The major boilerplate that occurs is in the factory. Each product create call would be at minimum 4 lines. Which has been reduced to a single line registration function. I also think this has one up on the Dr. Dobb’s implementation in that we’re using the compiler a bit more heavily, and we don’t limit the product classes to a single hierarchy. You can find the eeyore library here.

All in all this was a fun exercise, and I look forward to doing it again. Until then stay healthy, and happy coding!

PL

I know quite certainly that I myself have no special talent; curiosity, obsession and dogged endurance, combined with self-criticism, have brought me to my ideas.
– Albert Einstein

YEG C++ Lightning Talks

Tuesday, Sep 15, 2020, 6:30 PM

Online event
,

2 Members Attending

Have you ever spent 15 minutes diving into the semantics of const correctness at a round table, only to have your Grandmother and Aunt look at you like you’re out of your mind? Maybe you dream of abstract syntax trees, while your eyes glaze over as your friends dive into their COVID wedding plans. If any of this sounds like you, read on! Express yo…

Check out this Meetup →

Join us virtually for our YEG C++ lightning talks!

References:

What is Type Erasure – Arthur O’Dwyer
Conversations: Abstract Factory, Template Style – Herb Sutter & Jim Hyslop
Understanding Abstract Factory Pattern – Harshita Sahai