Archives 03/20/2023

Conclusion– Strategy, Abstract Factory, and Singleton Design Patterns

The Strategy design pattern is very effective at delegating responsibilities to other objects, allowing you to hand over the responsibility of an algorithm to other objects while keeping its usage trivial. It also allows having a rich interface (context) with behaviors that can change at runtime.As we can see, the Strategy pattern is excellent at helping us follow the SOLID principles:

  • S: It helps extract responsibilities from external classes and use them interchangeably.
  • O: It allows extending classes without updating its code by changing the current strategy at runtime, which is pretty much the actual definition of the OCP.
  • L: It does not rely on inheritance. Moreover, it plays a large role in the composition over inheritance principle, helping us avoid inheritance altogether and the LSP.
  • I: By creating smaller strategies based on lean and focused interfaces, the Strategy pattern is an excellent enabler of the ISP.
  • D: The creation of dependencies is moved from the class using the strategy (the context) to the class’s consumer. That makes the context depend on abstraction instead of implementation, inverting the flow of control.

C# Features

If you noticed C# features you are less familiar with, Appendix A explains many of them briefly.

Next, let’s explore the Abstract Factory pattern.

The Abstract Factory design pattern

The Abstract Factory design pattern is a creational design pattern from the GoF. We use creational patterns to create other objects, and factories are a very popular way of doing that.The Strategy pattern is the backbone of dependency injection, enabling the composition of complex object trees, while factories are used to create some of those complex objects that can’t be assembled automatically by a dependency injection library. More on that in the next chapter.

Goal

The Abstract Factory pattern is used to abstract the creation of a family of objects. It usually implies the creation of multiple object types within that family. A family is a group of related or dependent objects (classes).Let’s think about creating automotive vehicles. There are multiple vehicle types, and there are multiple models and makes for each type. We can use the Abstract Factory pattern to model this sort of scenario.

Note

The Factory Method pattern also focuses on creating a single type of object instead of a family. We only cover Abstract Factory here, but we use other types of factories later in the book.

Design

With Abstract Factory, the consumer asks for an abstract object and gets one. The factory is an abstraction, and the resulting objects are also abstractions, decoupling the creation of an object from its consumers.That allows adding or removing families of objects produced together without impacting the consumers (all actors communicate through abstractions).In our case, the family (the set of objects the factory can produce) is composed of a car and a bike, and each factory (family) must produce both objects.If we think about vehicles, we could have the ability to create low- and high-end models of each vehicle type. Here is a diagram representing how to achieve that using the Abstract Factory pattern:

 Figure 7.4: Abstract Factory class diagramFigure 7.4: Abstract Factory class diagram 

In the diagram, we have the following elements:

  • The IVehicleFactory interface represents the Abstract Factory. It defines two methods: one that creates cars of type ICar and another that creates bikes of type IBike.
  • The HighEndVehicleFactory class is a concrete factory implementing the IVehicleFactory interface. It handles high-end vehicle model creation, and its methods return HighEndCar or HighEndBike instances.
  • The LowEndVehicleFactory is a second concrete factory implementing the IVehicleFactory interface. It handles low-end vehicle model creation, and its methods return LowEndCar or LowEndBike instances.
  • LowEndCar and HighEndCar are two implementations of ICar.
  • LowEndBike and HighEndBike are two implementations of IBike.

Based on that diagram, consumers use the concrete factories through the IVehicleFactory interface and should not be aware of the implementation used underneath. Applying this pattern abstracts away the vehicle creation process.