Abstract Factory

      Comments Off on Abstract Factory

Home Forums Programming Software engineering Patterns design Abstract Factory

This topic contains 0 replies, has 1 voice, and was last updated by  Васильев Владимир Сергеевич 2 weeks ago.

  • Author
    Posts
  • #4099

    This article represents a popular design pattern Abstract Factory, points out its advantages and disadvantages and demonstrates its structure in C# code example.

    Speaking of popularity, the Abstract Factory is one of the most well-known design patterns described by the “gang of four.” It allows you to create interfaces of objects somehow related to each other. With this factory you will be able to create groups of objects that implement the general behavior.

    The advantage of this pattern is that it isolates the particular classes, making it easy to replace the product family.

    However, I have to note that it also has a certain disadvantage – for example, if you want to increase the functional abilities of the factory by adding a new type of product, you will have to edit all the existing implementations of Abstract Factory. And this might be unacceptable, because for example, if you have already created a number of specific factories, and they are already being used.

    To demonstrate an example of applying the Abstract Factory pattern, let’s turn again to our favorite confections.

    The rivalry in the confectionery market is simply crazy nowadays. The only ones not involved in the production of sweets and pastries are children, the elderly and bloggers: the first risk to fail, self-consuming all manufactured products, for the second it is in the past, and the third simply have no time for that.

    There are plenty of confectioneries and workshops , and they all produce basically the same.

    Whichever confectionery we choose to go, everywhere we can buy cakes, eclairs, muffins and so on. They even have the same names everywhere. But for some reason, we do not buy them just at some random places. We go to the same place where the quality of products is already familiar. Or we may buy cakes from one bakery, eclairs from another, and muffins from some other , but all at the same confectionery shop.

    But anyway, we never knock directly on the bakery’s door and we do not choose a cake right there, instead of that we buy it in the shop . For sure we don’t know much about the process of making the cake there, we can only guess, and of course we never participate in the cooking process directly (and it’s probably for the better).

    Now imagine that we want to make a model of the situation described above using C# code . And in this case, the Abstract Factory design pattern is just perfect.

    Let’s define a base class for any type of confectionery, and in terms of the Abstract Factory pattern – this is AbstractFactory:

    abstract class Confectionery
    {
      public abstract Cake MakeCake();
      public abstract List<Muffin> MakeMuffins(int number);
      public abstract List<Profiterole> MakeProfiteroles(int number);
    }

    Now we define the base classes for three types of confectionery products which we could order, and in terms of the Abstract Factory that will AbstractProductA, AbstractProductB and AbstractProductC:

    abstract class Muffin
    {
       public string Name { get; protected set; }
     
    }
    abstract class Cake
    {
       public string Name { get; protected set; }
    }
    abstract class Profiterole
    {
       public string Name { get; protected set; }
    }

    Done. Now we can create particular implementations of factories and products. Let’s start with the factory:

    class CityCenterConfectionery : Confectionery
    {
       public override Cake MakeCake()
       {
          return new PragueCake("an amazing Prague Cake");
       }
     
       public override List<Muffin> MakeMuffins(int number)
       {
          List<Muffin> muffins = new List<Muffin>();
          for (int i = 0; i < number; i++)
          {
              muffins.Add(new FrenchMuffin(String.Format("a beautiful French Muffin {0}", i+1)));
          }
          return muffins;
       }
     
       public override List<Profiterole> MakeProfiteroles(int number)
       {
           List<Profiterole> profiteroles = new List<Profiterole>();
          for (int i = 0; i < number; i++)
          {
              profiteroles.Add(new ChocolateProfiterole(String.Format("a lovely Chocolate Profiterol {0}", i+1)));
          }
           return profiteroles;
       }
    }

    And now the products:

    class PragueCake: Cake
    {
        public PragueCake(string name)
        {
           Name = name;
       }
    }
    class ChocolateProfiterole : Profiterole
    {
       public ChocolateProfiterole(string name)
       {
          Name = name;
       }
    }
    class FrenchMuffin: Muffin
    {
       public FrenchMuffin(string name)
       {
          Name = name;
       }
    }

    To keep things simple and not to include anything extra to the code example we shall only use the class entry point for testing its work:

    class Program
    {
       static void Main()
       {
         //creating an instance of a confectionery shop     
         var confectionery = new CityCenterConfectionery();
     
         //order sweets from the city center confectionery shop
         Console.WriteLine(confectionery.MakeCake().Name);
         confectionery.MakeMuffins(7).ForEach((m) => Console.WriteLine(m.Name));
         confectionery.MakeProfiteroles(5).ForEach((p) => Console.WriteLine(p.Name));
       }
    }

    And here goes the result:

    an amazing Prague Cake
    a beautiful French Muffin 1
    a beautiful French Muffin 2
    a beautiful French Muffin 3
    a beautiful French Muffin 4
    a beautiful French Muffin 5
    a beautiful French Muffin 6
    a beautiful French Muffin 7
    a lovely Chocolate Profiterol 1
    a lovely Chocolate Profiterol 2
    a lovely Chocolate Profiterol 3
    a lovely Chocolate Profiterol 4
    a lovely Chocolate Profiterol 5

    Of course, the point of this example is not in what we see here as a Console output. The point is that we have built a system which is targeted to create groups of objects that match certain interfaces, while we completely isolate the process of creating these objects from a class that requests them. The only possible way to get a specific product is to refer to the factory class which produces it.

    Of course, the example here is quite sketchy, but hopefully, it helped the readers of this article to understand the essence of the Abstract Factory design pattern.

You must be logged in to reply to this topic.