In this post, I am going to give you a brief information regarding the design patterns used in Software Architecture Process. For any software designing process, selecting a particular set of patterns is very essential. Once the patterns are finalized, then development team can proceed with the implementation using stable and robust architecture.
Before actually jumping on to the design patterns, we must first see what design principles are and should be followed:
- One and Close Principle ( Open for Extension, Closed for Modification )
- Prefer Delegation over Inheritance
- Single Responsibility Principle
- Interface Segregation
- Program to Interface rather than implementation ( Similar to Polymorphism )
There are basically three category of design patterns. These are designed by the GOF ( Gang of Four ). They are as follows:
- Creational Patterns
- Structural Patterns
- Behavioral Patterns
This pattern is used to get the objects of the same level of hierarchy. We have a factory which provides the required instances of the classes based on the need.
Examples: Iterator, DriverManager.getConnection() etc.
- Abstract Factory
This pattern is used to get the concrete objects of the same family. We have one abstract factory interface which is implemented by multiple concrete factory’s and thus, producing the required objects.
When most of the attributes of the objects are similar (only 1 or 2 are dissimilar) then we use this kind of pattern. In this pattern, we don’t make a simple copy of the object. We basically do a memory to memory copy (shallow copy) of the object which is quite faster. (This is done by clone() method). To do a deep copy of the objects (recommended), it is necessary to implement Cloneable (for custom objects) and not primitives.
Example: busManager.clone() etc.
When we want to one big object based on different small objects, then we use Builder Pattern. It has a Director which calls the build method inside Builder to build the object. Builder is basically an interface which is implemented by all it’s concrete builders and thus, their specific build method is called.
When we want one or limited instances of the class, then we use Singleton pattern. It is comparable with Mono-state class (which has all methods static). But in Singleton pattern, all methods are object based and it’s constructor is private.
This pattern provides a simple method or methods for the user to access the complete system functionality. Different types of façade are Optional Facade and Mandatory Facade.
Examples: Web Services, Connect and Disconnect of the most complicated System etc.
When we want to have a compatibility between interfaces of different packages, then Adaptor is provided. Class Adapter and Object Adapter are the different types of this pattern. Object Adapter is used as it deals with objects are redundancy of the attributes is very less as compared to Class Adapter.
There is a single way adaptation possible using one adapter. If we need both way adaptation, then two separate adapters are needed.
Examples: MouseEventAdapter, ListAdapter etc.
This pattern is used to decouple the interfaces of the system. The main purpose of Bridge pattern is to decouple abstraction from implementation.
Examples: MVC patterns, 3 layer architecture etc.
Decorator as the name suggests provides the extra functionality to the existing feature. It decorates the given object based on the user selections. Decorator class has ‘has-a’ and ‘is-a’ relationship with interfaces.
Examples: ReadLine() function (It internally uses Read function and using the decorator, provides reading line by line) etc.
When we want to apply one action to it’s child and when parent and child are on the same type, then we use Composite Pattern.
Example: Storage Units like Folder and File. Operations like select, deselect, copy, cut, paste can be applied to them and delete on folder also deletes all the files it contains.
It is used to reduce the memory space. When unique no. of objects are very small as in comparison with total no. of objects, then Flyweight pattern is used. The objects are immutable.
Example: String Class.
It is just like a surrogate/ placeholder to the main object. The different types of the proxy pattern are Virtual Proxy, Remote Proxy, Protection Proxy and Smart Reference Proxy. In real, Lazy Initialization is always preferred over proxy.
When basic structure is needed for the different classes, then template pattern is used. It also provides the consistency, usability between different pages. There is a final method which is acting as structural method and other methods are primitive methods.
Example: Thread.start() is a template method which internally calls run() method of Thread class.
- Chain of Responsibility
It follows the workflow model and also uses the segregation of responsibilities. Handler interface (having HandleRequest() method) is used which is implemented by multiple Concrete Handler’s. It has a successor.
In this, the object is encapsulated into a request object.
Two things that need to be kept in mind before using this pattern are 1) Chain should not be broken. If any new developer forgets to call successor, then it will create problems. So, use Template pattern with this approach. 2) There should be a fixed end.
If there is one or more dependency on one object, then Observer pattern is used. It is also called as ‘Publish/Subscribe’ pattern.
Example: Implementations of Event Listener in Java, C# etc.
In this pattern, the request object is encapsulated and passed to invoker. Invoker then processes the request object and executes the command. The encapsulation of the request object is same as we discussed in Chain of Responsibility pattern.
When we want an object to alter its state based on behavior, then State pattern is used. The state objects can be shared and can be implemented as Singletons.
In this pattern, the state transition occurs frequently which is not the case with Strategy pattern (We will discuss this later in strategy pattern)
Example: Traffic Lights etc.
When there are many ways to go from one point to another point, then use strategy and perform the action. User selects strategy at the start.
When we compare this pattern with State pattern, state transition occurs very frequently but the strategy once decided continues to be one till application processing lasts. It captures the abstraction in an interface and buries implementation details in derived classes.
Strategy is basically an algorithm which is exchangeable and vary independently.
Example: Game levels (Normal, Hard, Extreme), Comparator, compare method is used in Collections.sort().
In this pattern, the reference to the main object is maintained. The encapsulation should not be broken. Caretaker should not tamper with the states. This pattern preserves encapsulation boundaries.
This pattern works on the different hierarchies of products. This fits best in for the requirements which are quite ad-hoc and not permanent.
This pattern lets you define a new operation without changing the classes of the elements on which it operates.
This pattern provides the best way to iterate on the collections without showing/representing it’s underlined representation.
Suppose we have a hash set and contains many null values inside it, then use HashSet iterator which skips the null values internally and only provides only valid values.
Example: Iterator class in Java, Enumerator in C# to iterate over the collections.
This pattern define an object that encapsulates how a set of objects interact. It reduces coupling between objects by keeping them from referring to each other explicitly.
Example: Web Server for Chat Room which handles communication between participants.
This pattern is just the use of the composite pattern to represent the grammar. The interpreter defines the behavior while the composite provides the structure.
Example: JVM has an interpreter which compiles the code based on the OS.
Now, we have seen what all patterns we can use to design the software. It is also important to think about what can be the things we should not do while designing patterns. These things are basically called as ‘Anti-Patterns‘.
Let’s take a look at each one of them on the group hierarchy level.
- Development Anti-Patterns
- Boat Anchor
- Cut and Paste Programming
- Dead End
- Fire Drill
- Functional Decomposition
- Golden Hammer
- Mushroom Management
- Coding Bad Smells
- Architectural Anti-Patterns
- Death Match Project
- Analysis Paralysis
- Death by Planning
- Irrational Management
- Project Mis-Management
- Management Anti-Patterns
- Architecture By Implication
- Auto generated Stovepipe
- Intellectual Violence
- Spaghetti Code
- Swiss Army Knife
You can also refer following links to get more information about the design patterns, examples and their implementation.
@MsWizKid Signing off,