Thursday, June 9, 2022

Design Pattern: Decorator Pattern

Chapters

Decorator Pattern

Decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class.

The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.

Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object. This example demonstrates decorator pattern.
public class ClientCode{

  public static void main(String[] args){
    Package standard = 
    new StandardPackage("My Package");
    Package business = 
    new BusinessPackage("My Company's Package");
    
    standard.pack();
    business.pack();
    System.out.println();
    
    //with decorator
    new PackageGiftWrap(business).pack();
    System.out.println();
    new PackagePlasticWrap(standard).pack();
  }
}

interface Package{

  void pack();
}

abstract class AbstractPackage implements Package{
  protected String packageName;
  
  AbstractPackage(String packageName){
    this.packageName = packageName;
  }
  
  public String getPackageName(){
    return packageName;
  }
  
}

class StandardPackage extends AbstractPackage{
  
  StandardPackage(String packageName){
    super(packageName);
  }
  
  @Override
  public void pack(){
    System.out.println
    (packageName + " with standard packaging " +
    "has been packed.");
  }
}

class BusinessPackage extends AbstractPackage{
  
  BusinessPackage(String packageName){
    super(packageName);
  }
  
  @Override
  public void pack(){
    System.out.println
    (packageName + " with business packaging " +
    "has been packed.");
  }
}

//abstract decorator
abstract class PackageDecorator implements Package{
  
  protected void setAddon
  (String packageName, String addon){
    System.out.println
    (addon + " add-on has been added to " +
     packageName);
  }
}

//concrete decorator
class PackageGiftWrap extends PackageDecorator{
  private Package itemPackage;
  
  public PackageGiftWrap(Package itemPackage){
    this.itemPackage = itemPackage;
  }
  
  @Override
  public void pack(){
    itemPackage.pack(); //delegation
    giftWrap();
  }
  
  private void giftWrap(){
    if(itemPackage instanceof AbstractPackage){
      AbstractPackage ap = 
      (AbstractPackage) itemPackage;
      System.out.println
      (ap.getPackageName() + 
       " has been gift wrapped.");
    }
    else
      System.out.println("Can't find package name!");
  }
}

//concrete decorator
class PackagePlasticWrap extends PackageDecorator{
  private Package itemPackage;
  
  public PackagePlasticWrap(Package itemPackage){
    this.itemPackage = itemPackage;
  }
  
  @Override
  public void pack(){
    itemPackage.pack(); //delegation
    plasticWrap();
  }
  
  private void plasticWrap(){
    if(itemPackage instanceof AbstractPackage){
      AbstractPackage ap = 
      (AbstractPackage) itemPackage;
      System.out.println
      (ap.getPackageName() + 
       " has been plastic wrapped.");
    }
    else
      System.out.println("Can't find package name!");
  }
}

Result
My Package with standard packaging has been packed.
My Company's Package with business packaging has been packed.

My Company's Package with business packaging has been packed.
My Company's Package has been gift wrapped.

My Package with standard packaging has been packed.
My Package has been plastic wrapped.
In the example above, we can independently add new functionalities to StandardPackage and BusinessPackage instances during run-time by using decorator classes. Decorator and bridge patterns have similar structure.

However, they have different purpose. Bridge pattern is used to separate two related hierarchies so that they can be expanded independently whereas decorator pattern is used to statically or dynamically add new functionalities to an instance related to decorator class instance.

Wednesday, June 8, 2022

Design Pattern: Composite Pattern

Chapters

Composite Pattern

Composite pattern is a partitioning design pattern. The composite pattern describes a group of objects that are treated the same way as a single instance of the same type of object.

The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.

These diagrams demonstrates composite pattern.
Diagram
Courtesy of Wikipedia

We can think of this method as a tree structure. A branch holds leaves and leaves are in a branch. In the diagram above, Component is a root branch and Composite is a child branch. Take a look at this example.
import java.util.List;
import java.util.ArrayList;

public class ClientCode{
  
  public static void main(String[] args){
    Package myRedPackage = 
    new RedPackage("Delivery Package", "packages");
    
    myRedPackage.addPackage(
    new RedPackage("My Colleague's Package", 
                   "Ballpens"));
    myRedPackage.addPackage(
    new RedPackage("My Package", 
                   "Pens"));
    myRedPackage.addPackage(
    new BluePackage("My Friend's Package", 
                    "Documents", true));
    
    myRedPackage.packageInfo();
    System.out.println();
    
    myRedPackage.getPackage(2).packageInfo();
    
    System.out.println();
    myRedPackage.removePackage(2);
    System.out.println();
    
    Package subPackage = 
    myRedPackage.getPackage(0);
    subPackage.packageInfo();
    System.out.println();
    
    subPackage.addPackage(
    new RedPackage("Optional Package", "Stamps"));
    subPackage.getPackage(0).packageInfo();
  }
}

//root 
abstract class Package{
  private List<Package> packageList;
  private String content;
  private String packageName;
  
  Package(String packageName, String content){
    packageList = new ArrayList<>();
    this.packageName = packageName;
    this.content = content;
  }
  
  public String getPackageName(){
    return packageName;
  }
  
  public String getContent(){
    return content;
  }
  
  public void addPackage(Package element){
    packageList.add(element);
  }
  
  public Package getPackage(int index){
    Package target = null;
    
    try{
      target = packageList.get(index);
    }
    catch(ArrayIndexOutOfBoundsException e){
      System.out.println("Invalid Index!");
    }
    return target;
  }
  
  public void removePackage(int index){
    String target = null;
  
    try{
      target = packageList.get(index).
      getPackageName();
      packageList.remove(index);
    }
    catch(ArrayIndexOutOfBoundsException e){
      System.out.println("Invalid Index!");
      return;
    }
    System.out.println
    ("Package "+ target +" is removed!");
  }
  
  abstract public void packageInfo();
}

//leaf
class RedPackage extends Package{
  
  RedPackage(String packageName, String content){
    super(packageName, content);
  }
  
  @Override
  public void packageInfo(){
    System.out.println("Name: " + 
    getPackageName());
    System.out.println("Color: Red");
    System.out.println("Parent: Package");
    System.out.println("Content: " + getContent());
  }
}

//composite
abstract class CompositeStandardPackage extends Package{
  private boolean isSpecial;
  
  CompositeStandardPackage(String packageName, 
                           String content, 
                           boolean isSpecial){
    super(packageName, content);
    this.isSpecial = isSpecial;
  }
  
  public boolean isSpecial(){
    return isSpecial;
  }
}

//leaf
class BluePackage extends CompositeStandardPackage{
  
  BluePackage(String packageName, String content,
              boolean isSpecial){
    super(packageName, content, isSpecial);
  }
  
  @Override
  public void packageInfo(){
    System.out.println("Name: " + 
    getPackageName());
    System.out.println("Color: Blue");
    System.out.println
    ("Parent: CompositeStandardPackage");
    System.out.println("Content: " + getContent());
    System.out.println("Is Special? " + isSpecial());
  }
}

Result
Name: Delivery Package
Color: Red
Parent: Package
Content: Packages

Name: My Friend's Package
Color: Blue
Parent: CompositeStandardPackage
Content: Documents
Is Special? true

Package My Friend's Package is removed!

Name: My Colleague's Package
Color: Red
Parent: Package
Content: Ballpens

Name: Optional Package
Color: Red
Parent: Package
Content: Stamps
In the example above, leaf and Composite classes can add, get and remove children(packages in this case). There are two types of child-related designs that we can use to design our composite tree structures. Take a look at this diagram.
Diagram
Courtesy of Wikipedia

In the example above, I used the "Design for Uniformity" design because the composite design pattern emphasizes uniformity over type safety. In "Design for type safety" design, only composite class and its subclasses can have children. This example in wikipedia demonstrates "Design for type safety" design.

Monday, June 6, 2022

Java Tutorial - Bridge Pattern

Chapters

Bridge Pattern

Bridge Pattern is a design pattern that is meant to "decouple an abstraction from its implementation so that the two can vary independently". For example, we have shape and we want to implement a color feature. To do this, we create a class for shape and color; combine them in one hierarchy.

The problem with this is that these two classes are going to be tightly coupled and we, programmers, avoid tight coupling if possible. To avoid tight coupling in this case, we will decouple a class of color from class of shape.

Class of shape will stand as an abstraction for class of shape color. Then, an implementation for coloring shapes of shape class will be delegated to class of shape color. We will use this diagram as reference:
Diagram
Courtesy of Wikipedia

This example demonstrates bridge pattern.
/*
Client
*/

public class ClientCode{
  public static void main(String[] args){
    Shape circ = 
    new Circle(new StandardShapeColorStyle());
    
    circ.setColorStyle("STYLE1");
    System.out.println
    ("Color style of this shape:");
    System.out.println
    (circ.getShapeColorStyle());
  }
}

/*
Abstraction
*/
abstract class Shape{
  private ShapeColorStyle scs;
  private String colorStyle;
  
  Shape(ShapeColorStyle scs){
    this.scs = scs;
  }
  
  //implementation of setColorStyle of
  //Shape class delegated to setColorStyle
  //of ShapeColorStyle
  public void setColorStyle(String style){
    if(scs == null){
      System.err.println
      ("ColorStyle instance not defined!");
      return;
    }
    colorStyle = scs.setColorStyle(style);
  }
  
  String getShapeColorStyle(){
    return colorStyle;
  }
}

class Circle extends Shape{

  Circle(ShapeColorStyle scs){
    super(scs);
  }
  
  //refined version of setColorStyle
  //of Shape class. I find this one
  //optional
  @Override
  public void setColorStyle(String style){
    System.out.println
    ("This shape is circle.");
    System.out.println
    ("Circle has infinite vertices.");
    System.out.println
    ("Setting color style...");
    super.setColorStyle(style);
  }
  
}

/*
Implementor
*/

interface ShapeColorStyle{
  String setColorStyle(String style);
}

class StandardShapeColorStyle implements 
                              ShapeColorStyle{
  private final String STYLE1 = "STYLE1";
  private final String STYLE2 = "STYLE2";
  
  @Override
  public String setColorStyle(String style){
    String colorStyle = null;
    
    switch(style){
      case STYLE1:
      colorStyle = "Color Style One";
      break;
      
      case STYLE2:
      colorStyle = "Color Style Two";
      break;
    }
    return colorStyle;
  }
}

Result
This shape is circle.
Circle has infinite vertices
Setting color style...
Color style of this shape:
Color Style One
One of the advantages of bridge pattern is that we can independently expand two related hierarchies. In the example above, Shape and ShapeColorStyle classes can be expanded without affecting each other.

Sunday, June 5, 2022

Design Pattern: Adapter Pattern

Chapters

Adapter Pattern

Adapter Pattern is a design pattern that makes two incompatible interfaces collaborate. We use adapter if a new codebase that we wanna add to our application is not compatible with our existing interface.

For example, we have an application that lists data in plain text format. Then, we have a third library that process analytics. This library is verified compatible with our application but the problem is that this library returns data in XML format. To resolve this problem, we can look for another library. However, even we find another library we need to verify if it's compatible with our application, which takes time.

Another solution is to modify the library itself. However, a lot of problems may arise. One of them is licensing issue, some libraries are protected by license and thus we can't just modify libraries. Another solution is to create an adapter which is a good solution to this problem.

There are two types of adapter pattern: Object adapter pattern and Class adapter pattern. Object adapter pattern implements the target(interface where another interface is gonna be converted) interface by delegating to an adaptee(interface that is gonna be converted to) object at run-time.

Class adapter pattern implements the target interface by inheriting from an adaptee class at compile-time. This example demonstrates object adapter pattern.
//client
public class ClientCode{

  public static void main(String[] args){
    PlainTextInterface plainText = 
    new XMLToPlainTextAdapter(new XMLAnalytics());
    
    plainText.displayData();
  }
}

//Assume our third party library has an
//interface
interface XMLInterface{

  String getAnalytics();
}

//Assume this is a third party library
class XMLAnalytics implements XMLInterface{
  private String content;
  
  XMLAnalytics(){
    content= "<data>Testing</data>";
  }
  
  @Override
  public String getAnalytics(){
    return content;
  }
  
}

//Our app's interface
interface PlainTextInterface{

  void displayData();
}

//Our app's class
class PlainTextDisplay implements PlainTextInterface{
  private String data;
  
  PlainTextDisplay(String data){
    this.data = data;
  }
  
  @Override
  public void displayData(){
    System.out.println("Data in plain text: " + data);
  }
}

//Adapter
//In object adapter pattern, we wrap adaptee interface and
//implements target interface
class XMLToPlainTextAdapter implements PlainTextInterface{
  private XMLInterface xml_analytics;
  
  XMLToPlainTextAdapter(XMLInterface xml_analytics){
    this.xml_analytics = xml_analytics;
  }
  
  @Override
  public void displayData(){
    String noTags = 
    xml_analytics.getAnalytics().
    replaceAll("[<][/]??.+?[>]","");
    
    System.out.println("XML converted to plain text");
    System.out.println("Data in plain text: " + noTags);
  }
}

Result
XML converted to plain text
Data in plain text: Testing
Next, let's implement class adapter pattern. First off, change XMLToPlainTextAdapter class to this:
class XMLToPlainTextAdapter 
      extends XMLAnalytics
      implements PlainTextInterface{
  
  @Override
  public void displayData(){
    String noTags = getAnalytics().
    replaceAll("[<][/]??.+?[>]","");
    
    System.out.println("XML converted to plain text");
    System.out.println("Data in plain text: " + noTags);
  }
}
Then, change ClientCode class to this:
public class ClientCode{

  public static void main(String[] args){
    PlainTextInterface plainText = 
    new XMLToPlainTextAdapter();
    plainText.displayData();
  }
}
The problem with class adapter pattern is that it doesn't work with all OOP languages. For example, java doesn't support multiple inheritance of classes; this pattern won't work with java if we have multiple adaptees in one adapter.

In the example above, one-way conversion has been implemented to our adapter. However, we can implement two-way conversion which converts XML to plain text and vice-versa.

To do this, we can implement both interfaces in one adapter or create another adapter for conversion from plain text to XML. In my opinion, the latter is more preferrable.

Saturday, June 4, 2022

Design Pattern: Prototype Pattern

Chapters

Prototype Pattern

Prototype pattern is a creational design pattern that copies(clone) an object rather than re-creating it. In Object Oriented Programming (OOP), objects are created by instantiating a class.

In java, there's a clone() method that we can use to clone an object rather than re-creating it via instantiation. In this pattern, we create an interface (or abstract class). Then, the client can use the interface to clone its concrete implementations. Take a look at this example.
import java.util.List;
import java.util.Random;

public class ClientCode{
  
  public static void main(String[] args)
                throws CloneNotSupportedException{
    Prototype protoA = 
    new ConcretePrototypeA("protoA");
    
    System.out.println("Original");
    protoA.displayList();
    System.out.println("\n");
    
    Prototype cloneObj = protoA.clone();
    System.out.println("Clone");
    cloneObj.displayList();
    System.out.println("\n");
    
    System.out.println("Compare Instance");
    System.out.println(
    protoA.compareListInstance(cloneObj.getList()));
  }
}

//factory class
interface Prototype extends Cloneable{
  
  Prototype clone() throws CloneNotSupportedException;
  void displayList();
  boolean compareListInstance(List<Integer> list);
  List<Integer> getList();
}

class ConcretePrototypeA implements Prototype{
  private List<Integer> numbers;
  
  ConcretePrototypeA(String name){
    Random rand = new Random();
    Integer[] values = new Integer[5];
    for(int i = 0; i < values.length; i++)
      values[i] = rand.nextInt(1000);
    numbers = java.util.Arrays.asList(values);
  }
  
  @Override
  public Prototype clone() throws CloneNotSupportedException{
    return (ConcretePrototypeA) super.clone();
  }
  
  public void displayList(){
    numbers.stream().forEach(v -> System.out.print(v + " "));
  }
  
  public boolean compareListInstance(List<Integer> list){
    return list == numbers;
  }
  
  public List<Integer> getList(){
    return numbers;
  }
  
}

Result(may vary)
Original
588 68 607 122 106

Clone
588 68 607 122 106

Compare Instance
true
You can use this pattern when you want to create another Object at runtime that is a true copy of the Object you are cloning. True copy means all the attributes of the newly created Object should be the same as the Object you are cloning.

Friday, June 3, 2022

Design Pattern: Builder Pattern

Chapters

Builder Pattern

Builder pattern is a design pattern that separates object creation from objects. It means that we dedicate a class to assemble every parts of an object that we wanna create instead of assembling parts directly in the class of the object. This pattern reduces the complexity of a class. Take a look at this example.
public class ClientCode{

  public static void main(String[] args){
    House myHouse =
    House.newBuilder("My House").
    installRoof("Gable").
    installWallpaper("Green").
    installTiles("Blue").
    installRooms(3).
    build();
    
    myHouse.houseInfo();
    System.out.println();
    
    myHouse = new 
    Director(
    House.newBuilder("My Another House")).
    construct();
    
    myHouse.houseInfo();
  }
}

class House{
  
  private String houseName;
  private String roof;
  private String wallpaper;
  private String tiles;
  private int rooms;
  private boolean garage;
  
  private House(String houseName){
    this.houseName = houseName;
  }
  
  public static House.HouseBuilder newBuilder(String houseName){
    return new House(houseName).new HouseBuilder();
  }
  
  public void houseInfo(){
    System.out.println("House Name: " + houseName);
    System.out.println("Roof: " + roof);
    System.out.println("Wallpaper: " + wallpaper);
    System.out.println("Tile Color: " + tiles);
    System.out.println("# of Rooms: " + rooms);
    System.out.println("Is there a garage? " + garage);
  }
  
  class HouseBuilder implements Builder{
    
    private HouseBuilder(){
      House.this.roof = "None";
      House.this.wallpaper = "None";
      House.this.tiles = "None";
      House.this.rooms = 0;
      House.this.garage = false;
    }
    
    @Override
    public House.HouseBuilder installRoof(String roof){
      House.this.roof = roof;
      return this;
    }
    
    @Override
    public House.HouseBuilder installWallpaper(String wallpaper){
      House.this.wallpaper = wallpaper;
      return this;
    }
    
    @Override
    public House.HouseBuilder installTiles(String tiles){
      House.this.tiles = tiles;
      return this;
    }
    
    @Override
    public House.HouseBuilder installRooms(int rooms){
      House.this.rooms = rooms;
      return this;
    }
    
    @Override
    public House.HouseBuilder installGarage(boolean install){
      House.this.garage = install;
      return this;
    }
    
    @Override
    public House build(){
      return House.this;
    }
    
  }
}

interface Builder{

  House.HouseBuilder installRoof(String roof);
  House.HouseBuilder installWallpaper(String wallpaper);
  House.HouseBuilder installTiles(String tiles);
  House.HouseBuilder installRooms(int rooms);
  House.HouseBuilder installGarage(boolean install);
  House build();
  
}

class Director{
  private Builder builder; 
  
  public Director(Builder builder){
    this.builder = builder;
  }
  
  public House construct(){
    House houseInstance = null;
    
    if(builder instanceof House.HouseBuilder){
      houseInstance = builder.
      installRoof("Dutch").
      installWallpaper("Blue").
      installRooms(4).
      installGarage(true).
      build();
    }
    return houseInstance;
  }
}

Result
House Name: My House
Roof: Gable
Wallpaper: Green
Tile color: Blue
# of Rooms: 3
Is there a garage? false

House Name: My Another House
Roof: Dutch
Wallpaper: Blue
# of Rooms: 4
Is there a garage? true
You may suggest that there are alternatives to this pattern. Let's assume you're suggesting to use a constructor:

... House(String roof, String wallpaper, String tiles, int rooms, boolean garage)
...


This alternative does make sense in the example above. However, what if want two types of builds of our house? also what if each part of a house in every build has different calculations. In this case, builder pattern is more preferrable. For example, we wanna calculate the size of a roof and each build has different ways of calculating roofs.

In this case, we can just add the calculations to their installRoof methods. Imagine coding two or more types of builds in your House. Your code can become harder to read. Using build pattern, we can encapsulate those builds and their functionalities. Making our House class more clear.

Another advantage of this pattern is that clients can build an object in step-by-step manner. Also, I didn't put any getter or setter methods in the example above but we can put those methods in the House class if we want to.

You might have noticed the Director class. This class contains pre-configured builds of our builders. If you have a build that you often use, you can add that builds in this class, so that you don't need to write your build code everytime you wanna use it. We can also use this class to save client's builds.

In java, some classes implement this pattern. HttpRequest.Builder and DateTimeFormatterBuilder are some examples of classes that implement builder pattern.

Wednesday, June 1, 2022

Degin Pattern: Abstract Factory Pattern

Chapters

Abstract Factory Pattern

Abstract factory pattern is just like factory pattern, but this pattern deals with a family of objects and its variants. For example, we are creating classes for two GUI component providers. Both create GUI components but they have different design.

We can use abstract factory method to create a class design in this scenario. Take a look at this example.
/*
Client
*/
import factories;

public class ClientCode{

  public static void main(String[] args){
    GUIComponentsFactory factory = 
    GUIComponentsFactory.
    selectFactory("Unix");
    Button createdButton = null;
    RadioButton createdRadioButton = null;
    
    if(factory != null){
      createdButton = 
      factory.createButton("MyButton");
      System.out.println
      ("Created Button: " + 
       createdButton.getName());
      System.out.println();
      
      createdRadioButton = 
      factory.createRadioButton("MyRadioButton");
      System.out.println
      ("Created Button: " + 
       createdRadioButton.getName());
    }
  }
}

/*
Factories
Assume classes below are part of factories package
*/

public interface GUIComponentsFactory{
  
  Button createButton(String name);
  RadioButton createRadioButton(String name);
  
  public static GUIComponentsFactory selectFactory(String provider){
    GUIComponentsFactory factory = null;
    
    switch(provider){
    
      case "Windows":
      factory = new CreateWinComponents();
      break;
      
      case "Unix":
      factory = new CreateUnixComponents();
      break;
    }
    return factory;
  }
}

class CreateWinComponents implements GUIComponentsFactory{
  
  CreateWinComponents(){}
  
  @Override
  public Button createButton(String name){
    return new WinButton(name);
  }
  
  @Override
  public RadioButton createRadioButton(String name){
    return new WinRadio(name);
  }
  
}

class CreateUnixComponents implements GUIComponentsFactory{
  
  CreateUnixComponents(){}
  
  @Override
  public Button createButton(String name){
    return new UnixButton(name);
  }
  
  @Override
  public RadioButton createRadioButton(String name){
    return new UnixRadio(name);
  }
}

/*
Objects
*/

pubic abstract class Button{
  private String name;
  
  Button(String name){
    this.name = name;
  }
  
  public String getName(){
    return name;
  }
  
}

class WinButton extends Button{

  WinButton(String name){
    super(name);
    System.out.println(name + 
    " Windows Button has been created!");
  }
}

class UnixButton extends Button{

  UnixButton(String name){
    super(name);
    System.out.println(name + 
    " Unix Button has been created!");
  }
}

public abstract class RadioButton{
  private String name;
  
  RadioButton(String name){
    this.name = name;
  }
  
  public String getName(){
    return name;
  }
  
}

class WinRadio extends RadioButton{

  WinRadio(String name){
    super(name);
    System.out.println(name + 
    " Windows Radio Button has been created!");
  }
}

class UnixRadio extends RadioButton{

  UnixRadio(String name){
    super(name);
    System.out.println(name + 
    " Unix Radio Button has been created!");
  }
}

Result
MyButton Unix Button has been created!
Created Button: MyButton

MyRadioButton Unix Radio Button has been created!
Created Button: MyRadioButton
Just like in factory pattern, factory superclass and objects superclass should be non-instantiable. In short, they can't be instantiated.

One of the advantages of abstract factory pattern over factory pattern is that this pattern implements greater abstraction than factory pattern. However, if you're not producing a family of objects, it's better to use factory pattern.

This pattern inherits the advantages and disadvantages of factory pattern. For more information, you may visit this website