Design Patterns
Tags: java, codenewbie, oop, wecoded
Published: 2022-06-18 08:52:58

Pertaining a good knowledge of strong Object Oriented(OO) topics is surely a great strength to have but considering knowing these concepts without having proper idea of OO Design Patterns can lead you to have some disastrous roadblocks when working on a real world application.

Here I have created a glossary for few known handy Design Patterns that can help us make our code more flexible, reusable an efficient. Hope it helps!

> _**Patterns aren’t invented, they are discovered**_

------------------------------------------------------------------
### **Pre-requisites**
  **1. Encapsulation** : object-oriented procedure of combining the data members and data methods of the class inside the user-defined class.

  **2. Abstraction** : the process of hiding certain details and showing only essential information to the user. Achieved using either abstract classes or interfaces.

  **3. Polymorphism** : the ability of an object to take many forms. This helps us perform the same action in different ways.

  **4. Inheritance** : mechanism in which one object acquires all the properties and behaviors of a parent object.

------------------------------------------------------------------

### **Behavior Patterns**

**1. Strategy Pattern**
_Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it_ .

_**Implementation**_
Let's say we have a _class Demo_ which needs to perform few operations dynamically. We create a _Rundemo class_ which uses a Strategy interface implemented by different operation classes say _Add(), Subtract() and Multiply()_ .

```
Step 1
Creating the interface:Strategy.java

public interface Strategy {
   public int operation(int num1, int num2);
}

------------------------------------------------------------------
Step 2
Create concrete classes implementing the same interface: OperationAdd.java

public class Add implements Strategy{
   @Override
   public int operation(int num1, int num2) {
      return num1 + num2;
   }
}

------------------------------------------------------------------
OperationSubstract.java

public class Subtract implements Strategy{
   @Override
   public int operation(int num1, int num2) {
      return num1 - num2;
   }
}

------------------------------------------------------------------
OperationMultiply.java

public class Multiply implements Strategy{
   @Override
   public int operation(int num1, int num2) {
      return num1 * num2;
   }
}

------------------------------------------------------------------
Step 3
Create Rundemo Class: Rundemo.java

public class Rundemo {
   private Strategy strategy;

   public Rundemo(Strategy strategy){
      this.strategy = strategy;
   }

   public int executeStrategy(int num1, int num2){
      return strategy.operation(num1, num2);
   }
}

------------------------------------------------------------------
Step 4
Use the Rundemo to see change in behavior when it changes its Strategy: Demo.java

public class Demo {
   public static void main(String[] args) {
      Rundemo rundemo = new Rundemo(new Add());		
      System.out.println("8 + 5 = " + context.executeStrategy(8, 5));

      rundemo = new Rundemo(new Substract());		
      System.out.println("8 - 5 = " + context.executeStrategy(8, 5));

      rundemo = new Rundemo(new Multiply());		
      System.out.println("8 * 5 = " + context.executeStrategy(8, 5));
   }
}

------------------------------------------------------------------
Step 5
Verify the output.

8 + 5 = 13
8 - 5 = 3
8 * 5 = 40
```
_**Key Points to remember**_
 - Favor composition over inheritance.
 - Encapsulate what varies.
 - Have a clear picture of HAS-A , IS-A relationships before 
   implementing.
 - Program to interfaces not implementations.

------------------------------------------------------------------
**2. Observer Pattern**
_Defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically. The use cases that involve updating, deletion and registration of multiple observers dynamically handled by one source often involves utilization of this pattern_ .

_**Implementation**_
Let's say we have a _class Demo_ which is a system that needs to perform few operations(e.g updating subject state) dynamically of a number of _observers_ with the help of a _Subject_ . We have created an _abstract class Observer_ and a _concrete class Subject_ that is extending class Observer. The _class Demo_ uses _subject class_ concrete class object to show observer pattern in action.

```
Step 1
Create Subject class : Subject.java

import java.util.ArrayList;
import java.util.List;
public class Subject {
	
   private List<Observer> observers = new ArrayList<Observer>();
   private int state;

   public int getState() {
      return state;
   }

   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }

   public void attach(Observer observer){
      observers.add(observer);		
   }

   public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   } 	
}

------------------------------------------------------------------
Step 2
Create Observer class : Observer.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

------------------------------------------------------------------
Step 3
Create concrete observer classes : BinaryStateStringObserver.java

public class BinaryStateStringObserver extends Observer{

   public BinaryStateStringObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) ); 
   }
}

------------------------------------------------------------------
OctalStringStateObserver.java

public class OctalStringStateObserver extends Observer{

   public OctalStringStateObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
     System.out.println( "Octal String: " + Integer.toOctalString( subject.getState() ) ); 
   }
}

------------------------------------------------------------------
HexaStateStringObserver.java

public class HexaStateStringObserver extends Observer{

   public HexaStateStringObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Hex String: " + Integer.toHexString( subject.getState() ).toUpperCase() ); 
   }
}

------------------------------------------------------------------
Step 4
Use Subject and concrete observer objects : Demo.java

public class Demo {
   public static void main(String[] args) {
      Subject subject = new Subject();

      new HexaStateStringObserver(subject);
      new OctalStateStringObserver(subject);
      new BinaryStateStringObserver(subject);

      System.out.println("First state change: 10");	
      subject.setState(10);
      System.out.println("Second state change: 12");	
      subject.setState(12);
   }
}

------------------------------------------------------------------
Step 5
Verify the output.

First state change: 10
Hex String: A
Octal String: 12
Binary String: 1010
Second state change: 12
Hex String: C
Octal String: 14
Binary String: 1100
```
_**Key Points to remember**_
 - Strive for loosely coupled designs between objects that 
   interact
 - Subjects update Observers using a common interface
 - Observers are loosely coupled in that the Subject knows nothing 
   about them, other than that they implement the Observer 
   interface.

_To be continued_ ...