Design patterns: Abstract factory and its types

Sławomir Kowalski
9 min readMay 1, 2018

--

Today, about an abstract factory and its types, a simple factory and a factory method. It will be a long lesson because it’s a bit to discuss, let’s do it

Each programmer has created a class object in the following way:

TestClass testclass = new TestClass();

This class is related to a concrete type, and creating something like that in the class is unacceptable, we remember the fifth principle of SOLID dependency inversion, to make the class dependent on abstraction and not on a particular type.

It would be better to assign an object to its interface:

ITestClass testclass = new TestClass();

So the factory pattern and all its variations are used to not create concrete types of class objects only abstract class types. Instead of giving the word new, we create a method that returns an abstract instance of the class object.

The abstract factory also serves to make the class that we create open to expansion but closed to modifications. Certainly you have also encountered such a code:

public void CreateObjectProduct(string type)
{
Product product;
if (type.equals("Bread"))
{
product = new Bread();
}
else if (type.equals("Apple"))
{
product = new Apple();
}
product.Create();
}

Well, we also met with a similar code in the second lesson of SOLID principles, when I discussed the open-closedprinciple, when we want to add another product we will have to modify this method, and then we would break the open-closed principle. This should be insulated inside the factory.

When should we use an abstract factory?

You have to remember that we use the factory where we want to cut off from creating an instance of a particular type of class.

This may be caused, for example, when the instance has a complicated logic to create its instance, or we want to create an instance of some classes, but its type will depend on additional parameters, then we should use the factory. Other reasons for using factories:

  1. The class has a large, overloaded constructor with many arguments — it can mean a badly designed class.
  2. The creation of a class instance is in the if condition and such logic should certainly be encapsulated inside the factory using inheritance and polymorphism, as I already mentioned when I discussed the second solid principle.
  3. If at the time of writing the code you do not know which instance to use, then also in this case you must use encapsulation.

You know that during the builder lesson we connected the factory with the builder, or rather a similar way of returning the object, look at the Shop class in the builder lesson, let’s look at the method that returns the roof object:

public IRoof GetRoof()
{
return roof;
}

Methods in the factory look very similar, they also return abstract object types, but the more precise concept of the factory is more complicated, I did this in order not to break the fifth rule of solid, normal builder would have concrete types of methods, with practical examples of using factories further in the lesson.

Simple factory

A simple factory works best in simple examples, because this solution has one big disadvantage that will be discussed soon, most of the time this solution is used by novice programmers, because this factory is simple to implement. Below is an example:

interface IProducts { }

class Apple : IProducts { }
class Orange : IProducts { }

class ProductsFactory
{
public IProducts CreateProduct(string fruit)
{
switch (fruit)
{
case "orange":
return new Orange();
break;

case "apple":
return new Apple();
break;

default:
throw new ArgumentException();
}
}
}

static void Main(string[] args)
{
ProductsFactory productsfactory = new ProductsFactory();

IProducts orange = productsfactory.CreateProduct("orange");

Console.ReadKey();
}

The code is very simple. Instances are returned in the form of an abstraction layer.

Only this one serious disadvantage, which has this solution is breaking the open-closed principle, when we want to add some other fruit, besides the class that we will have to add (adding new classes is not a solid rule violation) we will have to expand our switch what already is a breach of the open-closed principle.

You can also use a static version of the class. Just mark the method as a static static word. Then you will not have to create an instance of the object each time. However, static classes are obviously more difficult to test.

Factory method

The factory method is the most commonly used type of factory, among programmers, it brings all the benefits of using factories and meets the second SOLID open-closed principle. Because instances are created in child classes of individual factories. Example:

public interface IPartShop { }

class Roof : IPartShop { }
class Floor : IPartShop { }
class Wall : IPartShop { }

public abstract class PartShopFactory
{
public abstract IPartShop BuildPartShop();
}

public class RoofFactory : PartShopFactory
{
public override IPartShop BuildPartShop()
{
return new Roof();
}
}

public class FloorFactory : PartShopFactory
{
public override IPartShop BuildPartShop()
{
return new Floor();
}
}

public class WallFactory : PartShopFactory
{
public override IPartShop BuildPartShop()
{
return new Wall();
}
}
static void Main(string[] args)
{
PartShopFactory pathShopFactory = new RoofFactory();

IPartShop roof = pathShopFactory.BuildPartShop();

Console.ReadKey();
}

As you can see, the factory class is now an abstract class. Logic in the switch has been replaced by the mechanism of polymorphism. Now if we want to add some other part of the store to build, just add the factory class, we do not have to change the factory class, so, the open-closed principle is accomplish.

Thanks to the use of the abstract class which is the factory method, we can have classes that will be inherited from it and use its methods, which means we have more possibilities than in a simple factory that has only one simple switch.

There are many advantages of the factory method here are the most important of them:

– complies with the open-closed principle, it is easier to modify later

– the main factory code may be invisible to the programmer, eg in a library, and will be able to expand it thanks to the open-closed principle

– the layer of abstraction that encapsulates the complex logic of creating object instances.

– derivative factories are easy to test, just enter the interface that they will meet.

Abstract factory

The abstract factory as the last of the varieties of factories is the most difficult to understand. The abstract factory is about creating related objects. The main rule is that an abstract factory have to provide an interface to create a family of objects, it is best to see it in an example to understand:

public interface IPartShop { }

class Roof : IPartShop { }
class Floor : IPartShop { }
class Wall : IPartShop { }

public interface IWorkers { }

class WorkersRoof : IWorkers { }
class WorkersFloor : IWorkers { }
class WorkersWall : IWorkers { }

public abstract class SpaceConstructionFactory
{
public abstract IPartShop BuildPartShop();
public abstract IWorkers AssignWorkers();
}

public class SpaceContructionRoofFactory : SpaceConstructionFactory
{
public override IPartShop BuildPartShop()
{
return new Roof();
}
public override IWorkers AssignWorkers()
{
return new WorkersRoof();
}
}

public class SpaceContructionFloorFactory : SpaceConstructionFactory
{
public override IPartShop BuildPartShop()
{
return new Floor();
}
public override IWorkers AssignWorkers()
{
return new WorkersFloor();
}
}

public class SpaceContructionWallFactory : SpaceConstructionFactory
{
public override IPartShop BuildPartShop()
{
return new Wall();
}
public override IWorkers AssignWorkers()
{
return new WorkersWall();
}
}

//Customer class, in it we make factory classes
class SpaceConstruction
{
private SpaceConstructionFactory spaceconstruction;

public SpaceConstruction(SpaceConstructionFactory spaceconstruction)
{
this.spaceconstruction = spaceconstruction;
}

public void MakeSpaceContruction()
{
var partshop = this.spaceconstruction.BuildPartShop();
var workers = this.spaceconstruction.AssignWorkers();
System.Console.WriteLine("Workers are assigned to build individual parts of the store");
}
}

static void Main(string[] args)
{
SpaceConstruction spaceconstruction;

spaceconstruction =new SpaceConstruction(new SpaceContructionFloorFactory());
spaceconstruction.MakeSpaceContruction();

spaceconstruction = new SpaceConstruction(new SpaceContructionRoofFactory());
spaceconstruction.MakeSpaceContruction();

spaceconstruction = new SpaceConstruction(new SpaceContructionWallFactory());
spaceconstruction.MakeSpaceContruction();

Console.ReadKey();
}

In the above example, the abstract class SpaceConstructionFactory is a factory that defines the family of objects. With the help of the composition, we have determined that the customer class and factory derived classes are dependent on each other. The most important element of the abstract factory is the customer class. Using the composition, we create a class containing the appropriate factory.

What are the benefits of factory patterns and their variations?

Advantages

Thanks to the factory, we obtain an abstract layer, which is responsible for creating objects connected only by a common interface. The most important advantages of using factories:

  1. It maintains class Dependency inversion principle, which combines only a common interface. Such classes are easier to test and less chance for errors when we modify these classes, instead of creating new classes, eg new Bread(), we create factory method that returns objects of the IProducts interface.
  2. It provides a layer of abstraction thanks to which it encapsulates the appropriate logic inside the factory. Encapsulation as the basis for object-oriented programming also brings other benefits, such as simplifying the code, and concealing logic between layers of abstraction.
  3. It complies with the open — closed principle — while expanding the class we have no fear of spoiling something.
  4. The code is shared, i.e. reusable once created can be used elsewhere in the system.

What are the disadvantages of the factory if it misuses it?

As I mentioned earlier, all patterns have to be used with common sense, referring to Uncle Bob’s opinion from the previous lesson, as you do not remember, return to her.

Disadvantages

  1. Creating a factory “in any case”, i.e. someone has a feeling that maybe he will want to initialize the object in a different way, that is, break the YAGNI (You do not gonna need it)
  2. Do not create a factory if there is a single big switch inside

General pattern structure of an abstract factory

Let’s see what the UML diagram of the factory pattern looks like:

It can be seen that the abstract factory often uses factory methods.

Relations with other patterns

  • Often, different patterns use the Factory method, eg a builder or prototype when flexibility is needed.
  • The classes of the abstract factory are often implemented using the factory method, but can also be implemented using a prototype
  • Patterns The Abstract Factory, Builder and Prototype can be implemented as Singletons
  • Often, the Builder’s implementation is combined with an Abstract factory to maintain flexibility and not create concrete types of classes.

Summary of the factory pattern

The pattern of an abstract factory is often considered as difficult (if not the most difficult) design pattern. This complication results from the fact that there are many possibilities to implement this pattern, in this lesson I showed only a small part of it. This pattern can be modified and combined with other patterns. Below is a small summary of factory pattern variations:

Simple factory

  • the simplest way to separate implementations from the interface.
  • no inheritance, no composition.
  • no customer class.
  • hard to test
  • breaking the open-closed principle

Factory method

  • it complies with the open-closed principle
  • there is always an inheritance mechanism
  • no composition
  • complicated logic is encapsulate
  • easy to test

Abstract factory

  • creates families of objects in some way related to each other
  • there is a mechanism of inheritance
  • there is a mechanism of composition
  • there is a dedicated customer class
  • breaks the open-closed principle

Summary

Long article came out

. I hope I have somehow brightened the operation of the factory pattern

That’s all about Abstract factory.

This content also you can find on my steemit blog https://steemit.com/design-patterns/@slawas/design-patterns-abstract-factory-and-its-types

And on my blog devman: http://devman.pl/programtech/design-patterns-abstract-factory-types/

In the next article, we will talk about the Prototype pattern.

As a standard, I remind you about the newsletter, which I send notifications about new entries and additional information about the IT world in general.

And NECESSERILY join the DevmanCommunity community on fb, part of the community is in one place

– site on fb: Devman.pl-Sławomir Kowalski

– group on fb: DevmanCommunity

Ask, comment underneath at the end of the post, share it, rate it, whatever you want.

--

--