Skip to main content

GoF Design Patterns - The Hot Spots

Intro

Now days, any programmer working with a language which conforms to the OOP paradigm, understands the power of Design Patterns (DP). A variety of great books are available for plain English interpretations for the various 23 GoF design patterns and the differences between them. Yet, there are still many controversies regarding how certain patterns differ and how they are related.

Design Patterns, at first glance, sometimes appear very similar, not to say identical. When searching answers in forums, articles and blogs, I have encountered in a wide range of responses, starting from "It's the same DP and the only difference is the intend of the developer" and reaching "the questioned DPs are completely different and I can't even understand your question". If you sense that the truth lays somewhere in the between those responses, this new series of posts might interest you.

This post is a first in a new series of posts, in which I will try to highlight specific particular parts (henceforth: 'Hot Spots') of the discussed DP, differentiating them from each other.
At times it will be the implementation which will make the difference, but almost always I will prove that 'similar' DPs where designed for completely different purposes.

In this post, I explain the relevant Design Patterns only when it is absolutely required in order to explain the difference between the various DPs, otherwise a link to a good article is supplied.
For the sake of this series, I am considering only the DPs listed in the original GoF book.

Before I begin, I wish to clarify three important ingredients used in every DP, briefly:
  • Inheritance
  • Composition
  • Inversion of Control & Dependency Injection (IoC & DI)

Inheritance vs Composition

Inheritance

When we first started learning OOP, one of the most important lessons we were taught was Inheritance. Although Inheritance is a critical OOP subject, it is almost never the best solution for your design issues. Inheritance couples the base class with it's inherited classes. If, for any reason, the base class implementation must change, all of it's subclasses, who use or override their base methods, will be affected.


If the base is an Interface, then every single additional method added to the interface will require adding the implementation to all of it's subclasses, even those that were not meant to implement the new implementation. i.e:
interface IRobot
    {
        void Talk();
        void OpenDoor();
        void CloseDoor();

        //* New capability
        void Walk();
    }

    class ChefRobot : IRobot
    {

        public void Talk()
        {
            //* Implementation
        }

        public void OpenDoor()
        {
            //* Implementation
        }

        public void CloseDoor()
        {
            //* Implementation
        }

        //* The application business logic dictates that ChefRobot doen't have the need to walk. 
        //* Walk() remain unimplemented.
        public void Walk()
        {
            throw new NotImplementedException();//* EXCEPTION !!
        }
    }

    class BabySitterRobot : IRobot
    {

        public void Talk()
        {
            //* Implementation
        }

        public void OpenDoor()
        {
            //* Implementation
        }

        public void CloseDoor()
        {
            //* Implementation
        }

        public void Walk()
        {
            //* New Walk capability implementation
        }
    }

"IRobot" has several methods that must be implemented by every Robot subclass. Suppose a time comes, and we decide to add a new 'Walk' capability. Adding Walk() method to "IRobot" forces us to implement Walk() method in every Robot subclass. The problem is that our application's business logic dictates that "ChefRobot" doesn't have the need to walk. By using Inheritance we are forced to add the method Walk() in "ChefRobot" and leave it unimplemented.

Composition Instead

Inheritance may be considered only on two conditions:

  • The relationship between the base and subclasses is stable by definition. There are no reasonable scenarios in which this relationship should break.
  • When the interfaces are kept very small to include only the minimum set of methods required to group the various classes implementations.
For example: Ferrari 458 is a car - If "ICar" will always be kept small, to represent only the Car's needs AND because Ferrari 458 will always be a car, inheritance can probably be a good solution, and we can to implement common functionalities

Additionally, inheritance can be used to solve an OOP design issue, and not to represent a hierarchic structure. The coupling can generally be tolerated because we are sure enough the overall design will not change on a daily basis.


In any other case composition should be considered.

Composition means that instead of inheriting the common functionalities from a common base class, the common functionalities are encapsulated in a dedicated class and made exposed via public properties.
Now, the developer has the flexibility to add/remove common functionalities as required, without influencing the entire architecture.

Reviewing our "IRobot" sample again, we should have left in "IRobot" only the smallest set of common capabilities for all robots, and only add the new "Walkable" class with a Walk() method. This class may be referenced by all the Robots that can walk.

 interface IRobot
    {
        void GetBatteryStatus();
        void PowerOn();
        void PowerOff();
    }

    class ChefRobot : IRobot
    {

        public TalkCapability TalkProperty { get; set; }
        public DoorHandleCapability DoorProperty { get; set; }

        public void GetBatteryStatus()
        {
            //* Implementation
        }

        public void PowerOn()
        {
            //* Implementation
        }

        public void PowerOff()
        {
            //* Implementation
        }
       
    }

    class BabySitterRobot : IRobot
    {
        public WalkCapability WalkProperty { get; set; }
        public TalkCapability TalkProperty { get; set; }
        public DoorHandleCapability DoorProperty { get; set; }

        public void GetBatteryStatus()
        {
            //* Implementation
        }

        public void PowerOn()
        {
            //* Implementation
        }

        public void PowerOff()
        {
            //* Implementation
        }

    }

When using a composition, there is merely a weak relationship between the implementation and the class hosting the implementation. Because the class only contains the implementation, any change to the class containing the implementation will not affect the implementation itself and vice-versa. In addition, classes that should not make use of a specific implementation will simply not include it.

Alert readers may be confused from this last statement, because my solution prevents developers from using all "Robot" subclasses in a unified way.
We are no longer able to call the Walk() method on an instance of "IRobot" because the Walk() method is not a part of the common interface anymore:

IRobot r = new BabySitterRobot();
r.WakCapability.Walk(); //*Compilation Error
To solve this kind of issue, where some objects need to be extended without influencing the entire architecture, we need to use a relevant, suitable DP (i.e. Decorator), but not via Inheritance.

IoC & DI

Inversion of Control (IoC) is a technique very popular for solving design issues (I am sure you already use it, maybe without knowing it's professional name).
In order to fully implement it's goal, IoC uses another sub-technique called Dependency Injection (DI).

IoC

In brief, IoC is used when a method's internal implementation relies on some other class capabilities.
Without IoC we could simply instantiate the required internal class and use it's capabilities whenever it was needed.
The problem with this approach is that the two classes are now tightly coupled:

In the example below, "BatteryStatus" is welded inside "ChefRobot". The GetBatteryStatus() method can only work with a specific fixed instance of the "BatteryStatus" class. If, for any reason, we would need to switch the behavior at runtime, occasionally instantiating a new "NiceBatteryStatus" class will become a living nightmare. In addition, any change to the "BatteryStatus" class will require changes in ChefRobot.GetBatteryStatus().

class ChefRobot : IRobot
  {
   ....
   public void GetBatteryStatus()
   {
       //* ChefRobot & BatteryStatus are tightly coupled
       BatteryStatus bs = new BatteryStatus (params);
       bs.DoSome();
       //* More work
   }

The goal of IoC is to decouple the concrete class instantiation from it's clients. This is done by encapsulating the creation of the class outside of our exposed method, thus making the exposed method use an external object.
In other words we are inverting the instantiation control to the ChefRobot's clients.

By doing so, "ChefRobot" is dependent upon the class interface but doesn't know the concrete implementation. The implementation may now vary.[see next sample]

DI

The Dependent class can be Injected (from here the name Dependency Injection) into it's client in three different ways:

  1. Interface DI - The exposed method will be refactored to receive the class' interface as a parameter and just call upon methods.
  2. Setter DI - The exposed method's class will add a new Setter method of "IClass" type. The concrete "IClass" object will be injected into this Setter method.
  3. Configuration DI - The exposed method will, internally, call on a configuration file that specifies the exact concrete type to instantiate.

The following sample demonstrates a better implementation using Setter DI:
 class ChefRobot : IRobot
  {
   ....
  //* Setter DI
  public IBatteryStatus BatteryStatus{ get ; set ; }
  public void GetBatteryStatus()
  {
     //* ChefRobot & BatteryStatus are NOT tightly coupled.
     //* Any IBatteryStatus object can be used

     //* Now the control of IBatteryStatus instantiation is inverst
     BatteryStatus.DoSome();

     //* More work
   }

Equipped with this information, we are now ready to understand some DP Hot-Spots. Within a couple of days I will post the first article of this series: Factory Method vs Abstract Factory.

Comments

The Best

Closures in C# vs JavaScript -
Same But Different

Closure in a Nutshell Closures are a Software phenomenon which exist in several languages, in which methods declared inside other methods (nested methods), capture variables declared inside the outer methods. This behavior makes captured variables available even after the outer method's scope has vanished.

The following pseudo-code demonstrates the simplest sample:
Main() //* Program starts from here { Closures(); } AgeCalculator() { int myAge = 30; return() => { //* Returns the correct answer although AgeCalculator method Scope should have ordinarily disappear return myAge++; }; } Closures() { Func ageCalculator = AgeCalculator(); //* At this point AgeCalculator scopeid cleared, but the captured values keeps to live Log(ageCalculator()); //* Result: 30 Log(ageCalculator()); //* Result: 31 } JavaScript and C# are two languages that support…

Formatting Data with IFormatProvider & ICustomFormatter

This post provides an internal overview of IFormatProvider & ICustomFormatter interfaces, and they way they are handled by .NET.

IFormatProvider is a .NET Framework Interface that should be used, by implementing its single public object GetFormat(Type) method, when there is a need to implement custom formatting of data like String and DateTime.

The public object GetFormat(Type) method simply returns an object that in turns is available to supply all available information to continue the formatting process. The Type passed in by the Framework is meant to give the implementor a way to decide which type to return back. Its like a Factory Method Design Pattern where the "formatType" is the type expected to be returned.
class MyProvider : IFormatProvider { public object GetFormat(Type formatType) { object result = null; //* Factory Method if (formatType == typeof( ICustomFormatter)) //* Some object, will be disc…

Design API for Multiple Different Clients

Today I want to talk about common design challenges related to architecture of robust APIs, designed to be consumed by multiple clients with different needs.

Our use case is the following: We need to build a N-Tier Web REST/SOAP API that is supposed to read/write data from a DB, perform some processing on that data and expose those methods to our API consumers.

In addition we have multiple different API clients each with different needs, meaning we can't just expose a rigid set of functions with a defined group of DTOs (Data Transfer Objects).
DTO vs POCO Before start diving I want to explain shortly the difference between these two controversial concepts.
DTO Objects that are designed to transfer data between edges (i.e. between processes, functions, server & clients etc'). Typically DTOs will contain only simple properties with no behavior.
POCO Objects that are designed to reflect the internal business data model. For example if you have an eCommerce platform you will…