This post(s) is an attempt to present the contrasting differences between several Creational Design Patterns in layman terms.
- Purpose of Design Patterns, (checkout)
- Familiarity with SOLID Design Principles (checkout)
- The patterns covered here are not bound to any programming language, this blog will not be containing any code snippet but only class diagrams. (how to class diagrams)
What are Creational Design Patterns?
Creational Design Patterns deal with object creation mechanisms, trying to increase efficiency, code reuse, and flexibility.
What are the different Creational Design Patterns?
- Factory Method
- Abstract Factory
Creational design patterns are all about creating new objects. In our case, let us consider the scenario of producing a new car — Maruti Suzuki Baleno.
Let us define the classes Car and CarCreator. CarCreator implements various methods to produce the car.
With the above system (or manufacturing plant), we can produce as many cars as we want. The problem occurs when the manufacturer launches a car — Brezza to the market. Brezza being an SUV model, cannot be produced in our current manufacturing plant.
An SUV model will require our CreatorClass to accept a different set of inputs like dimensions, chassis, engine, etc.
A supervisor (developer) going through the manufacturing plant (codebase) introduces Factory Method Pattern to fix the situation. He introduced the concepts of abstract and concrete components.
The product Car is considered an abstract class interface; Baleno and Brezza become the concrete products.
Another abstract class CarCreator is defined with multiple methods. The method — CreateCar() is an abstract class that accepts a parameter — type to produce the Cars — Baleno and Brezza. The method QualityAssurance() becomes a separate and common process outside of CreateCar() that every Car has to go through. Furthermore, the concrete classes BalenoCarCreator and BrezzaCarCreator defined the concrete method for CreateCar() that creates Baleno or Brezza.
Here CreateCar() is a FactcoryMethod, which is the only decision-maker in producing the required Car.
In general terms fig(d) represents the class diagram for Factory Abstract Method. Note the dependency ConcreteCreatorB & ConcreteCreatorA on ConcreteProductB & ConcreteProductA.
The Maruti Suzuki’s Hatchback and SUV we produced were very well received in the Indian market. So much so that, the cars became bestsellers in their respective segments. This quickly gained the attention of competitors and a few joint ventures with Maruti Suzuki were proposed.
One such was Toyota — Maruthi Suzuki joint venture. According to this, Toyota gets to rebrand the 2 cars (Baleno & Brezza) as Glanzo and Urbancruiser.
The Glanzo and Urbancruiser had only cosmetic changes from their counterparts. It would make a lot of sense to manufacture the cars in the already existing plant, we now have to tweak the system (codebase) with the very minimal change to not strain the production pace (efficiency) of the current market bestsellers.
One way is to create more concrete products — Glanzo and Urbancruiser in addition to Baleno and Brezza. This would also need the two additional factories GlanzoCarCreator and UrbancruiserCarCreator. This approach creates a lot of repetitive code, which is not advised.
The first thing the Abstract Factory pattern suggests is to identify and explicitly declare interfaces for each distinct product.
Between the four models Baleno, Brezza, Glanza, and Urbancruiser, we define two interfaces based on types of cars — Hatchback and SUV. These interfaces are realized with concrete classes distinguished by their families (manufacturers). This approach provides scope for welcoming more manufacturers 🤑 . Fig (e) represents the interface for Hatchback, the interfaces for SUV or even MPV types can be deduced the same way.
Next, the Abstract Factory needs to be declared as an interface with a list of creation-methods for each type (of car) belonging to the family. That is createHatchback() and createSUV(); these abstract methods return the products of the type Hatchback and SUV respectively.
For each variant of the family, we create a concrete class based on the CarFactory interface i.e, MarutiSuzukiCarFactory and ToyotaCarFactory. These concrete classes take care of adding their family essence in building the product.
When the client code(factory) wants to produce a Hatchback car, it does not have to know the family variant. Irrespective of the family, the client code executes move() stop() as declared in the interface of cars.
Below is an overview of the class diagram, the client code invokes CarFactory() expecting the return type — Car (here, Hatchback).
Abstract Factory classes are often based on a set of Factory Methods. Many designs start by using Factory Method and evolve towards Abstract Factory when customization is required.