Architecture & DesignOverview of Design Patterns for Beginners

Overview of Design Patterns for Beginners

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction

Modern software development needs to address complex business requirements. It also needs to take into account factors such as future extensibility and maintainability. A good design of a software system is vital to accomplish these goals. Design patterns play an important role in such systems. While learning a programming language beginners often focus on language syntax and usage techniques. However, it is also important to understand the basics of good software design. To that end this article gives a quick understanding of design patterns. It discusses what design patterns are, their benefits and classification.

What are Design Patterns?

A real world software system is supposed to solve a set of business problems. Most of the modern languages and tools use object oriented design to accomplish this task of solving business problems. Designing a software system is challenging because it not only needs to meet the identified requirements but also needs to be ready for future extensions and modifications. A software design problem may have more than one solution. However, the solution you pick should be the best in a given context. That is where design patterns come into the picture.

Before we go into more detail of design patterns, let’s try to get a basic idea about them using a non-software example. Suppose you are standing at the base of a mountain and have been given the task of reaching its top by the end of the day. Assuming that you are unaware of the route to the mountain top, what will you do? Of course, you will start to climb up as per your own understanding. You may use your past experience, you may use your intuition and obviously you will also use your common-sense while finding the route. At times you may go in the right direction and at other times you may wander away. Finally after making all these efforts you may reach the top. Can you see the pain point here? Your lack of knowledge about the right route makes it extremely difficult for you to decide the best possible route.

There may be multiple routes that take you to the top but not all will do so in the same amount of time and effort. Some routes might be tough to walk but they might take you to the top in less time. Some other routes might be easy to walk but they may take too much time. Which one is the best route? There cannot be a single answer to this question. Depending on your physical strength, available time and external conditions, such as weather, you need to compromise on a route as the “best”.

In the preceding example, you were unaware of any of the routes leading you to the top. What if somebody gives you a detailed map along with all possible routes, along with pros and cons of each? Obviously, you will be in a much better position to begin your journey.

Let’s try to draw a parallel in terms of a software system designing. Suppose you have been given a software design problem to solve. As a developer you may attempt to solve it based on your own skills and experience. However, if you start the design from scratch you may end up spending too much time and effort. Additionally, you may not know whether your design is the best possible design in a given context. That is where design patterns come into picture.

Simply put a design pattern is a proven solution to solve a design problem. A design pattern provides a template or blueprint for solving a software design problem at hand. Why are design patterns better than a “from scratch” solution? That’s because thousands and thousands of developers all over the world have used them successfully to solve a design problem. Thus they are proven solutions to recurring design problems. Additionally, since design patterns are well documented you have all the information needed to pick the right one.

A design pattern is usually expressed by the following pieces of information:

  • Name : A design pattern usually has a name that expresses its purpose in nutshell. This name is used in the documentation or communication within the development team.
  • Intent : Intent of a pattern states what that pattern does. Intent is usually a short statement(s) that captures the essence of the pattern being discussed.
  • Problem : This refers to a software design problem under consideration. A design problem depicts what is to be addressed under a given system environment.
  • Solution : A solution to the problem mentioned above. This includes the classes, interfaces, behaviors and their relationships involved while solving the problem.
  • Consequences : Tradeoffs of using a design pattern. As mentioned earlier there can be more than one solution to a given problem. Knowing consequences of each will help you evaluate each solution and pick the right one based on your needs.

Note that the above list is just the minimum information needed to describe a pattern. In practice, a few more aspects may also be needed to be expressed.

As an attempt to catalog popular design patterns Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides documented around 23 design patterns in their book titled “Design Patterns: Elements of Reusable Object-Oriented Software”. These design patterns are the most popular and commonly used patterns today. These patterns are often termed as Gang of Four (GoF) patterns since they are documented by these four authors.

What are the Benefits of Using Design Patterns?

The discussion about design patterns should have given you some idea about their benefits. Let’s quickly identify and summarize these benefits here:

  • Design patterns help you to solve common design problems through a proven approach.
  • Design patterns are well documented so that there is no ambiguity in the understanding.
  • Design pattern may help you reduce the overall development time because rather than finding a solution you are applying a well known solution.
  • Design patterns promote code reusability and loose coupling within the system. This helps you deal with future extensions and modifications with more ease than otherwise.
  • Design patterns promote clear communication between technical team members due to their well documented nature. Once the team understands what a particular design pattern means, its meaning remains unambiguous to all the team members.
  • Design patterns may reduce errors in the system since they are proven solutions to common problems.

Classification of Design Patterns

Now that you understand what design patterns are and what their benefits are, let’s see how they are classified. The GoF design patterns are classified into three categories namely creational, structural and behavioral.

  • Creational Patterns : Creational design patterns separate the object creation logic from the rest of the system. Instead of you creating objects, creational patterns create them for you. The creational patterns include Abstract Factory, Builder, Factory Method, Prototype and Singleton.
  • Structural Patterns : Sometimes you need to build larger structures by using an existing set of classes. That’s where Structural Patterns come into picture. Structural class patterns use inheritance to build a new structure. Structural object patterns use composition / aggregation to obtain a new functionality. Adapter, Bridge, Composite, Decorator, Facade, Flyweight and Proxy are Structural Patterns.
  • Behavioral Patterns : Behavioral patterns govern how objects communicate with each other. Chain of responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template method and Visitor are Behavioral Patterns.

Example of a Design Pattern – Singleton

Now that you know the purpose and benefits of design patterns, let’s conclude this article by looking into a simple example of design patterns. In this example you will use Singleton design pattern. As mentioned earlier, Singleton is a creational design pattern. The intent of the Singleton design pattern is as follows:

To ensure that only one instance of a class is created and to provide a global point of access to the object.

The above intent tells us that Singleton is useful when you wish to create one and only one instance of a class in the system. Consider a case where you are building a class that represents some costly system resource. Since the resource is expensive you wish to ensure that the users of  the class create only one instance of the class to avoid any wastage of the resources. Singleton pattern can be used to enforce such a functionality.

Consider the following class written in C# that uses Singleton pattern.

public class CostlyResource
{
    private CostlyResource()
    {
        //nothing here
    }

    public DateTime LastRequestedOn { get; private set; }

    private static CostlyResource instance = null;

    public static CostlyResource GetInstance()
    {
        if(instance==null)
        {
            instance = new CostlyResource();
        }
        instance.LastRequestedOn = DateTime.Now;
        return instance;
    }
}

The above code creates a class named CostlyResource. The constructor of the class is made private so that you cannot instantiate it from outside of the class. The CostlyResource class has just one public property, LastRequestedOn, that stores the DateTime at which the last request for the object instance was made. Then the code creates a static instance of CostlyResource class and sets it to null. This variable is static because it needs to be shared with multiple calls. It then creates a static method named GetInstance(). The GetInstance() method is responsible for creating an instance of CostlyResource and stores it in the instance variable. It also sets the LastRequestedOn property to the current DateTime value. Finally, instance is returned to the caller.

The CostlyResource class can be used in some other part of the system like this:

static void Main(string[] args)
{
    CostlyResource obj1 = CostlyResource.GetInstance();
    Console.WriteLine(obj1.LastRequestedOn);
    System.Threading.Thread.Sleep(2000);
    CostlyResource obj2 = CostlyResource.GetInstance();
    Console.WriteLine(obj2.LastRequestedOn);

    if(Object.ReferenceEquals(obj1, obj2))
    {
        Console.WriteLine("obj1 and obj2 are pointing to the same instance!");
    }

    Console.ReadLine();
}

The above code creates a variable of type CostlyInstance (obj1) and points it to the instance returned by GetInstance() static method. It then outputs the LastRequestedOn property on the Console. The code then halts the execution for a couple of seconds by calling the Sleep() method of Thread class. It then creates another variable of type CostlyInstance (obj2) and calls GetInstance() again to obtain the instance. To prove that object pointed to by obj1 and obj2 is one and the same the code uses ReferenceEquals() method of the Object class. The ReferenceEquals() method accepts the two instances to compare and returns true if they are pointing to the same object. If you run the above code you will get an output as shown below:

Pointing to the Same Instance
Pointing to the Same Instance

Summary

Design patterns offer proven solutions to recurring design problems. GoF design patterns are widely used by developers and are classified into three categories – creational, structural and behavioral. This article presented a quick overview of design patterns. It also discussed Singleton design pattern along with its C# implementation.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories