Design patterns Ep.1 - Creational - Factory Method

Design patterns Ep.1 - Creational - Factory Method

I wanted to take this chance and start this mini series on talking about design patterns. As it is my first attempt to share knowledge online via a LinkedIn article, I will try to organize my thoughts properly and be as simple and pragmatic as I possibly can. Talking for this specific topic will be an absolutely fantastic educational experience for me and I am looking forward for it.

Let's start talking about design patterns. But what are those all about? Design patterns are not about a specific implementation that you can copy and paste in your code, nor a library or framework you can use. Design patterns are simply solutions to commonly occurring problems in software. You can think of them like pre-made blueprints that you can customize to solve a recurring design problem in your code.

All patterns can be categorized by their intent. The three most common groups are:

  • Creational, which provide object creation mechanisms that increase flexibility and reuse of existing code.
  • Structural, which explain how objects and classes are assembled into larger structures, while keeping those flexible and efficient.
  • Behavioral, which describe the communication and the assignment of responsibilities between objects.

Let's start our journey by investigating the Factory Method pattern, which is a creational one.

Problem

Let us understand the Factory Method Design Pattern with one simple example. We are going to develop an application for rendering buttons based on some random choice made by an imaginary user. Our requirement is, we will ask the user to select the button style to render to the screen. Once the user selects the button, then we need to simulate the rendering of this particular button, by simply writing some message in the console.

Let's see how to achieve this without using the Factory Method Design Pattern in C#.

First of all we need to create the IButton interface (could also be an abstract class), that will expose the operations a button should have. So, create a class file with the name IButton.cs and then copy and paste the following code in it:

No alt text provided for this image

Next we need to create some concrete buttons like below:

No alt text provided for this image
No alt text provided for this image

Now in the client code, we will ask the user to select the IButton Type. And based on the selected button, we will create an instance of any one of the above two IButton implementation classes:

No alt text provided for this image

The above code implementation introduces?the following problems

  1. Tight coupling between the client class (Program) and concrete IButton classes (WindowsButton, HTMLButton)
  2. If we add a new button, then also we need to modify the Main method by adding an extra if-else condition, which adds overhead both in the development and also in the testing process

One way to overcome the above problem is by using the simple factory design pattern, which states that you can create an object without exposing the object creation logic to the client and the client refers to the newly created object using a common interface.

Create a class file with the name?ButtonFactory.cs?and then copy and paste the following in it:

No alt text provided for this image

With the above we can modify our client code as follows:

No alt text provided for this image

What are the problems of using the simple factory pattern?

  1. If we need to add any new button, then we need to add a new if / else condition in the CreateButton method of the ButtonFactory class. This violates the open/closed principle (O in SOLID).
  2. We also have a tight coupling between the ButtonFactory class and concrete implementations of the IButton interface (WindowsButton, HTMLButton).

We can overcome the above problem by using the Factory Method Design Pattern, which provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. In other words, factory method lets a class defer instantiation to subclasses. Let's examine some details of the pattern.

Structure

No alt text provided for this image

Participants

  • <<interface>> Product (IButton): Defines the interface of objects the factory method creates.

No alt text provided for this image

  • ConcreteProduct (WindowsButton, HTMLButton): Provide various implementations of the Product interface.

No alt text provided for this image
No alt text provided for this image

  • <<abstract>> Creator (Dialog): Declares the factory method, which returns an object of type Product. The creator's subclasses usually provide the implementation of this method. Creator may also define a default implementation of the factory method that returns a default ConcreteProduct object.

No alt text provided for this image

  • ConcreteCreator (WindowsDialog, WebDialog): Concrete creators override the factory method to return an instance of a ConcreteProduct type.

No alt text provided for this image
No alt text provided for this image

  • Client code:

No alt text provided for this image

The output of the above code for the "Web" configuration type would be:

No alt text provided for this image

On the other hand, if we changed our Main method's code and called the Initialize method, using the "Windows" configuration type the output would be:

No alt text provided for this image

Applicability

Use the Factory Method pattern when:

1) A class can't anticipate the class of objects it must create

2) A class wants its subclasses to specify the objects it creates

3) Classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.

You can find the source code for the above example here.

That's all for today. Cheers!

要查看或添加评论,请登录

社区洞察

其他会员也浏览了