A general reusable solution to a common design problem.
Design Patterns? more-sky
Design Patterns
A design pattern provides a general reusable solution to a common design problem.
These are well-tested solutions to common problems and issues we run into in software development. They are best practices for solving common software design problems that occur again and again.
There are many design patters, and they are categorized under three main categories: Structural, Behavioral, and Creational.
We?re not going to cover all of them for sure, but, some of them. Most of the commonly used ones are already explained in DesignPatterns (GitHub).
Design Principles And Design Patterns
Design principles are guidelines that aim to achieve the desirable goals of a good design. Design patterns are solution for common design problems that use design principles to achieve these desirable goals of a good design.
Singleton Pattern
Singleton pattern falls under the creational design patterns.
In your application, you may need to have only one instance of an object at any time. Singleton pattern ensures that there is only ever one single instance of a class, it prevents any other object from being instantiated from that class.
There are 3 different ways to implement the singleton pattern, each one has it?s own strengthens and pitfalls.
We are going to use Java for the purposes of demonstration.
Classic Singleton
This is the most simple way to implement the singleton pattern.
The idea is simple, having a static reference variable assigned to null initially, and then you check if it?s null, return new instance, if not, return the current reference variable. This is done inside a static method. So, no new object will be instantiated.
Remember to keep the constructor as a private, so you won?t allow object to be instantiated in any part of your application. The next snippet will make it more clear.
public class SingletonPattern { private static SingletonPattern myInstance = null; private SingletonPattern() {} public static SingletonPattern getInstance() { if (myInstance == null) { myInstance = new SingletonPattern(); } return myInstance; }}
In your main, or any part of the application, here is how you can get the latest instantiated object
SingletonPattern curInstance = SingletonPattern.getInstance();
This approach is not convenient when you have multi-threading. Next is a proper solution to this problem.
Synchronized
The solution is to have the method getInstance synchronized. It will ensure that there is no more than one instance from a class In a multi-threaded environment.
public static synchronized SingletonPattern getInstance() { if (myInstance == null) { myInstance = new SingletonPattern(); } return myInstance; }
But, you need to know that synchronization is expensive. It takes more time to run, and we?ll pay for this cost every time we call getInstance method. Here?s another solution opposite to eager instantiation.
Eager Instantiation
Rather than doing check if myInstance is assigned to null or not, we assign it initially to a new instance. So, whenever the class is loaded by the JVM, the object will be created.
public class SingletonPattern { private static SingletonPattern myInstance = new SingletonPattern(); private SingletonPattern() {} public static SingletonPattern getInstance() { return myInstance; }}
But, it also has it?s own pitfalls, what if the object won?t be always needed?, and what if the object is very heavy and complex, hence it will slow down the system?. This approach will create the object when the class is loaded even if it?s not needed.
Summary
It?s clear that there are trade-offs, it depends on your needs.
Use the classic approach if you don?t have multi-threading operations, and if you have, there are two other options.
One, if you don?t care about the performance issues of synchronization and the object won?t be always needed use the synchronized approach.
Two, if the object will be always needed, use the eager instantiation approach.
Strategy Pattern
Strategy pattern falls under the behavioral design patterns.
It?s very useful when you have an object which has some behaviors that could be changed during the run-time.
It?s common practice to separate what varies from what stay the same; separate those behaviors from the class of that object, treat each one of the behaviors as a separate class that implements an interface.
In Design Principles, we?ve mentioned in ?Protected Variations? principle that interfaces are a solution for minimizing the impact of the parts of the system that are more likely to change. This pattern uses this principle to solve a common problem.
Example: Customer Payment
Let?s say that you have an application that tries to initiate a payment of a customer, but the problem is, the customer may choose to pay with paypal, or with credit card, where each of them has a different implementation.
We might say ?Ok, why not to have a method for paypal and another one for credit card??. This sounds reasonable for now, but what if you want to extend the methods of payment?. We will end up having many methods in one class, which is not a good case practice.
Class Diagram
A composition relationship between the customer and the payment interface, where each payment method inherits setPayment method. The composition relationship implies the idea of HAS-A relationship.
Strategy Pattern
Putting All Together ? Customer Payment: Download the code snippet, and share if you find it useful.
Command Pattern
Command pattern falls under the behavioral design patterns.
It?s solution to a problem when an object has to perform some commands during the run-time; we don?t know which commands needs to be executed.
You start separating those commands in encapsulated classes. Each class is implementing an interface that has a method called execute.
It?s the same principle as in the stratgey pattern; separate what varies from what stays the same.
Example: Read, Update, Delete Commands
We have the invoker object represents the admin, where the admin of the system can perform different commands. We have the command interface, where all commands are inheriting from it.
And we have the receiver object, which will be used by the inheriting command sub classes to perform the requested command.
Class Diagram
A composition relationship between the admin and the command Interface, where each command method implements execute method.
Command Pattern
Putting All Together ? Read, Update, Delete Commands: Download the code snippet, and share if you find it useful.
State Pattern
State pattern is a behavioral software design patter.
It?s used for the system that has different states to navigate between them based on some interactions during the running time. States are in form of objects, where each state object handles a specific kind of user interaction.
The interactions maybe external interactions from the users, or internally from the system itself.
Again, the same principle also applies here; separate what varies from what stays the same. So, we need to encapsulate these states as they will be changed during the run time.
Example: Microwave
In our example, imagine that you have a microwave, that has an initial state called waiting, and whenever the user press on start button, it moves to working state, and at this point the user can either pause or stop the microwave.
In case of pause it will move to a third state called paused, and in case of stop, it will revert back to waiting state.
States
We start creating a class for each state, each of these states will inherit from an interface called State.
It has a list of methods; ?start?, ?pause? & ?stop?. Notice that each state class will handle these methods, these are the interactions the user can make.
The user doesn?t need to know anything about the states, the user just perform some interactions; ?start?,?pause, and ?stop?.
So, what if the user clicks on pause while the system in waiting state. Inside the class of the waiting state, it should handles if the user wants to navigate to a wrong state, maybe you can display an error.
Class Diagram
A composition relationship between the microwave and the state interface.
The microwave class handles the interactions of the user, by asking the current state object to handle this interaction, which in turn navigate from one state to another (if needed). So, we only care about creating an instance from the microwave class.
This decreases the dependency, and the user will only care about the Microwave rather than each state.
State Pattern
In this class diagram, I didn?t add the getters and setters for each of the private state in microwave class. You can assume they are included.
Putting All Together ? Microwave: Download the code snippet, and share if you find it useful.