About Design Pattern
Design pattern is just like cookie cutter, a general templated solution for common or similar problem in a software product. Each pattern can be said as template solution, which can solve a particular design problem in the software code.
You may wonder this is what we have been calling Algorithm, did something change? No Algorithm and Design Pattern are two different concept for solving a particular problem. Algorithm is exact steps need to be followed to get the desired results, where as Design Pattern is best practices to solve common problems when designing a software application.
An analogy to an algorithm is like following maps to reach a destination, but with design pattern is more like choice of transport used, for shorter distance walk, then cycle, car, if in water then boat/ship or via air and so on. As design pattern allows developer to provides suggestion and patterns, but implementation is up to him/her.
The choice of programming language is very important because it decides the patterns could be used.
Need of Design Patterns
Object Oriented Programs (OOP) are made of objects, is hard when decomposing a system into objects. As there are may factors come into picture such as encapsulation, granularity, dependency, flexibility, performance, evolution, readability, reusability, security and so on. These have be addressed over a period of time and built as design patterns.
Instead of each time reinventing the same wheel, we can use the proven patterns in the development process.
Development time saved, as already these patterns have the template which could be used but making required changes.
As these patterns are proven solution, tested in various scenarios will help us to overcome the edge cases which could occur later after the implementation or productionized. Avoids burning the fingers again.
Ease to communicate the idea and talk in the same language.
As these patterns where not just built overnight, each pattern would have gone through various iteration. Makes its more reliable to use.
Design Principles
Before we discuss about design patterns its also very important to know about the Design Principles as it helps us in creating more maintainable, understandable, and flexible software.
The SOLID principles were introduced by Robert C. Martin in his 2000 paper “Design Principles and Design Patterns.”, later Michael Feathers built up and created the SOLID Acronym.
SOLID stands for:
S - Single-responsibility Principle
Class should hold only one responsibility, so when there is new change it should be only for the single functionality.
O - Open-closed Principle
Class should be open for extension but closed for modification. This allows the class to be stable avoiding new bugs.
L - Liskov Substitution Principle
Allowing the subclass to independently working even when the parent class is not available or can be said subclass would be able to replace parent class. Hence the dependency of the parent class can be vanished if the child can operate fully without altering the desirable properties of the program.
I - Interface Segregation Principle
Larger interfaces should be split into smaller ones, allowing the class to use only the required ones.
D - Dependency Inversion Principle
Instead of high level modules depending on low level modules, both should be be implemented on abstractions.
Classification of Design Patterns
Originally Design patterns were categorized into 3 sub classifications based on the problem it solves. But to my wonder could find 4 types in wiki, may be later it got added. As I find all the 4 are valid sub classification, lets see what is holds.
Singleton
Ensures a class only has one instance at any given time and provides a global access to the object.
Eg: When you write in stdout, its the same for all the packages or modules. There cannot be multiple file descriptor for a single stdout.
Abstract factory
Provides an interface for creating similar or same family of classes without the class definition.
Eg: When designing class for car, bike, auto we can have abstraction of Vehicle having methods like no of wheels, speed, and so on.
Factory
Defines a family of classes and let the factory method decide which class needs to be instantiated.
Eg: When designing transport service, there would be car, bike or auto services available. The book any option will act as a Factory class which will book either of this service based on the destination.
Builder
Break down the complex structure into simple objects and building the complex object by series of step by step process.
Eg: Assume you are building coffee vending machine, first option would be selecting water or milk, then adding coffee or tea, and then adding sugar or not. Like wise step by step adding small objects to build a product.
Dependency Injection
Makes the class independent and decoupled so it can be for their integration and testing.
Eg: When you build a system to book tickets, it could be easily decoupled either for booking movies or bus tickets the system varies. The same class can be used for both the system depending on where its plugged.
Lazy initialization
Delays the construction of the values until the data is actually called or needed.
Eg: When you define arrays in python it will not know and not allocate memory in huge sizes. Once you start using linearly the memory will be allocated.
Multiton
Updated version of singleton, instead of holding one instance Multiton holds group of instances created and reserved to access globally.
Eg: Lets say holding a dictionary of output methods, for error print in stderr else in stdout
Object pool
Object pool is a container which contains some amount of objects where the cost of initializing the class is high. So, when an object is needed its taken from the pool, and later after using it is pushed back to available in the pool. So it may be unavailable until it is put back.
Eg: Let's say you want to create array of database connections and reserve it in the array and use them when needed and return them back to the pool once used.
Prototype
Creates the new object by copying the existing object rather creating the object from scratch, allowing to hide the complexity of making new instances.
Eg: When you build car of specific type and want to replicate it, using prototype you can make a exact copy of the object with its values.
Structural Patterns: Deals with the composition of classes or objects. As how to assemble the objects and classes into larger structures which creates new functionality while still flexible to extend and efficient to use. Below are few patterns:
Adapter
Create an interface to enable communication between the two or more incompatible classes. Adapter lets the classes work together that couldn't work otherwise because of the incompatible interfaces.
Eg: Mobile phone chargers when you are in India you use a different style plug but whereas in US you have different plug option, does that mean need to replace mobile. No we can use an adapter that fits in different countries accordingly.
Bridge
Split the larger or complex classes of similar types into two separate hierarchies, by decoupling the abstraction from its implementation so both of them independently vary.
Eg: Let say you want to build a Vehicle it could be car or bike. I have parent class as Vehicle and sub classes as Car and Bike. Now I have requirement introducing Petrol or Electric. It would hard to have these combinations like Car Petrol and Car Electric or Bike Petrol and Bike Electric. Rather here I have another Interface called RunsOn where it can be extended to Petrol and Electric. Finally in the Vehicle class RunsOn is the object.
Composite
Compose the objects like a tree structure building hierarchy then we can work with these object as individually
Eg: We would want to build approval work flow, first level will be immediate manager and next would be boss's boss and so on. Finally we will have CEO. Here the hierarchy is built.
Decorator
Placing object inside wrapper objects this helps to enable additional/extending features on the wrapper layers of the object.
Eg: Authentication is a good example, when you are in office logging in it will ask for username and password. The same application when accessed from outside will ask for username and password and MFA. Later if you typed password wrongly twice it will be wrapping to security questions. So you could see the layers are built on top.
Extension Object
Anticipate the object interface needs to be extended in future. Additional interfaces can be added.
Eg: Lets say I need to build an app for Android, but would create interface called platform. As later we can have this running in other OS.
Facade
Provides the simple high level interface for a complex system making it easier to use.
Eg: Making an order in Amazon, later all the other tasks right from dealing with vendor to delivery is taken care.
Flyweight
Sharing the common objects in different contexts, in-order to save space supporting large number of objects saving and using efficiently.
Eg: Moving to example of building car or bike. I would need spare parts for each many instead of saving each of its parts in different parts occupying ram. Initialize them in common and use the appropriately.
Module
Encapsulation of both the private and public methods and variable in single object. Protecting the states and behaviour of being accessed from other classes.
Eg: Let say you want to build House class, you will have locker as private where it cannot be accessed from outside.
Proxy
Providing the surrogate or placeholder for another object to control access, in simple terms ability to perform an action on behalf of someone.
Eg: When you forward invite on behalf of someone. On a lighter no when you give proxy attendance of your friend who skipped the class.
Chain of responsibility
In this pattern the responsibilities are handled in a chain format, where each handler gets the request and see if it can handle if not pass it to the next handler.
Eg: When you click a video, it will first look into the local cache if available. Else the request will go the CDN. If not found will reach the application server. If not found finally get it from the db. Here chain of responsibility is performed.
Command
Calling an object by passing parameters to it, allowing the class to work on the parameters and result. This allows to serve different requests, queue or log requests and support undoable operations. The Execute method of the command knows how to bring all the pieces together to get the work done.
Eg: Unix command is the good example for this, lets take “ls” command it takes various options and displays the output based on the options passed.
Interpreter
While given a language with a defined grammar, an interpreter class uses to define this and provide a interpreter to make meaning out of the sentences in the language.
Eg: SQL query is defined a particular format and we need a parser to make meaning out of the query.
Iterator
Provides a way to access the elements of an collection object, traversing sequentially without exposing the underlying implementation of the class.
Eg: List, stack, tree, queue are some of the example of the Iterator class.
Mediator
Reduces the chaotic interaction between objects. Mediator works as a middle man to collaborate between objects. Promotes loose coupling by keeping objects only referring the mediator class.
Eg: Load balancer could be said as middle man, where the different clients do not interact with different servers sitting. Each talks to the load balancer, and load balancer will talk to the server and reply back the response to the client.
Memento
Storing the state of object without compromising on encapsulation or details of the class implementation.
Eg: Undo operation while performing in the word edit.
Observer
Subscribe-Publish can be also called to this pattern. Here there can be multiple object subscribing to the parent class and the publish will send the messages or changes to all the subscribed dependents.
Eg: You have an output which needs to be sent as email, stored in db and viewed in html. Here you can have one output class as publisher and all others as subscribers. When the output is generated, it passes to the subscribed list.
Servant
Servant is used for providing some behaviour to a group of classes. Instead of defining that behaviour in each class or in the common parent class - it is defined once in the Servant.
Eg: In a mobile we have several features related to Bluetooth, we can isolate this class and call in the master class. So the servant class features will be called when required, without overloading the master phone class.
State
Enables the object to change when the internal state of the class changes. The object will appear as the change happened in class.
Eg: When a phone is locked it can only perform certain actions, but where as when the phone is unlocked it can perform different set of actions. The internal state of phone decides the course of actions.
Strategy
Defines a family of algorithms and encapsulate them in one. While client using the strategy decides which class to be used.
Eg: Coming back to transport service, you have car, bike and auto grouped, as a user you can decide based on the budget and time which to pick.
Template
Defines the skeleton of an algorithm in the parent class, allowing the child classes override specific steps of the algorithm without changing its structure.
Eg: Building different models of Tata car, well the primary structure remains the same but only few customization is done based on the model.
Visitor
Enabling a operation performed on the object structure without changing the class of elements on which it operates.
Eg: Imagine you are car seller, when you visit professionals you would prefer selling sedan, for teens would prefer sports and kids battery cars. Ideally you are selling but based on the object structure it operates.
Concurrency Patterns: Provides effective patterns when dealing with either multiple threads or multiple computations happening in the same time.
Active Object
- Active Object pattern separates invocation of the method from its execution. That means the requests called from the client but not been executed directly, rather it is added to the queue maintained in the different object (Active Object). These requests will be running in its own thread of control but invoking asynchronously by picking up from the queue. This pattern is recommended when avoiding race condition and execution of the request in queue handled by the scheduler.
Eg: When you attach multiple files in the gmail, each will be running async.
Balking
- The word balk means hesitate or unwilling to accept, which actually matches with the pattern type. In Balking pattern the execution of the object occurs only if its present in particular state, else it will balk or in simple words throw an exception saying the state of the object is not matched hence balking. The state is maintained internally.
Eg: Designing a running car, when the car is not started but pressed acceleration it should balk. Similarly if the car is in acceleration mode but also pressing the break, it should again balk.
Double checked locking
- We have seen Singleton before, where an object can be initialised only once. But assume we are running in threads, there is a possibility of the multiple object created by each thread. To avoid using double checked locking pattern where the object is check twice before the performing the operation.
Eg: Continuing with our Singleton pattern, to have singleton pattern implemented we create a global variable and verify it is null just then create an object. Now when this is running in threads, its execution is not under user control rather it is under kernel control. Let's see where we can have problem, the first thread checking if the value is null, yes its null. Now the execution moves to second thread it checks if the value is null, yes its null. Now the execution moves to first thread the object is created, similarly it happens with second thread. So our object is no more called once, well its been created twice. In double checking the global variable is checked if its null, yes then perform lock and then again check if the object is null if yes then create the instance of the class.
Guarded suspension
- When running in threads we would need to check if the lock is acquired as well precondition is met before performing the operation. In this pattern the object method call is suspended until the precondition is met, we can say it acts as guard.
Eg: Let's say we are building an app where it needs to access the photos folder, but it cannot until we have go ahead from the user. So here the precondition would be acceptance of the user before performing the operation.
Monitor Object
- Monitor pattern controls the concurrent access of the method of the object. Let say concurrently two or more threads are calling a method at a same time, only one thread can execute this particular method
Eg: Assume we are having multiple threads writing in same files causing mixed up of the information, can use this pattern, allowing one thread to write at a time.
Thread pool
In this pattern we maintain pool of threads, waiting for the concurrent execution. This allows us to speed of the process, avoiding creation and destruction of threads for short-lived tasks.
Eg: Creating a pool of threads to process quick user queries, where the performance is important and usually it would be single response, such as status of ticket and so on.
Use a Design Pattern
Select the design pattern based on the requirement, study the patterns and it similar patterns and drill down patterns which fits the best.
Understand the cons and pros of the selected design pattern
Get the template code
Build on top of the template by defining the classes based on the application requirement
Challenges using Design Patterns
Every solution has or creates new problems or challenges, the same goes to design patterns.
Not every design pattern can be used or needed in each programming languages
Modern programming languages may have simple approach to resolve the solution
For not all problems design patterns can be used
Conclusion
We have seen what is design pattern and design principles. Classification and subtypes of the design patterns is covered. Finally the pros and cons of using a design pattern. These are not the complete list of design patterns we have many more and many more are yet to be discovered. We have not covered distributed system design patterns here, Leader and Follower is one type of de.

No comments:
Post a Comment