Table of Contents

— title: Design pattern layout: post category: Emacs tags: org jekyll —

1 design pattern

1.1 singleton   drill

1.1.1 code

// private and static member call instance 
// in the getInstance or Instance function(public) return instance and new it if it's not existed.

   public class SingleObject {

      //create an object of SingleObject
      private static SingleObject instance = new SingleObject();

      //make the constructor private so that this class cannot be
      //instantiated
      private SingleObject(){}

      //Get the only object available
      public static SingleObject getInstance(){
         return instance;
      }

      public void showMessage(){
         System.out.println("Hello World!");
      }
   }



   public class SingletonPatternDemo {
      public static void main(String[] args) {

         //illegal construct
         //Compile Time Error: The constructor SingleObject() is not visible
         //SingleObject object = new SingleObject();

         //Get the only object available
         SingleObject object = SingleObject.getInstance();

         //show the message
         object.showMessage();
      }
   }


   Step 3

   Verify the output.


   Hello World!

1.2 factory method pattern   drill

  1. 作一個 interface, member function is draw
  2. rectangle, circle, square 都 inherited from shape
  3. 作一個工廠,可生產 shape
  4. 用 factory.generate(string), 來決定生產哪個 shape 出去

1.2.1 code

//  Step 1
// Create an interface.
// Shape.java
public interface Shape {
   void draw();
}


// Step 2
// Create concrete classes implementing the same interface.
// Rectangle.java


public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}


// Square.java


public class Square implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}


// Circle.java


public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}


// Step 3

// Create a Factory to generate object of concrete class based on given information.

// ShapeFactory.java


public class ShapeFactory {

   //use getShape method to get object of type shape
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();

      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();

      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }

      return null;
   }
}


// Step 4

// Use the Factory to get object of concrete class by passing an information such as type.

// FactoryPatternDemo.java


public class FactoryPatternDemo {

   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();

      //get an object of Circle and call its draw method.
      Shape shape1 = shapeFactory.getShape("CIRCLE");

      //call draw method of Circle
      shape1.draw();

      //get an object of Rectangle and call its draw method.
      Shape shape2 = shapeFactory.getShape("RECTANGLE");

      //call draw method of Rectangle
      shape2.draw();

      //get an object of Square and call its draw method.
      Shape shape3 = shapeFactory.getShape("SQUARE");

      //call draw method of circle
      shape3.draw();
   }
}


// Step 5

// Verify the output.


// Inside Circle::draw() method.
// Inside Rectangle::draw() method.
// Inside Square::draw() method.

1.3 abstract factory   drill

1.3.1 desc

一個 abstract class factory 產生 abstract 的產品,ex, abstract class 只生成
border and button, 讓他的 implementation 去決定要生成哪種.

  適用性[編輯]
  在以下情況可以考慮使用抽象工廠模式:
  一個系統要獨立於它的產品的建立、組合和表示時。
  一個系統要由多個產品系列中的一個來配置時。
  需要強調一系列相關的產品物件的設計以便進行聯合使用時。
  提供一個產品類別庫,而只想顯示它們的介面而不是實現時。

  優點[編輯]
  具體產品從客戶代碼中被分離出來
  容易改變產品的系列
  將一個系列的產品族統一到一起建立

  缺點[編輯]
  在產品族中擴充功能新的產品是很困難的,它需要修改抽象工廠的介面

1.3.2 code

abstract factory :
the factory which create abstract objects

class Button; // Abstract Class

class MacButton: public Button {};

class WinButton: public Button {};

class Border; // Abstract Class

class MacBorder: public Border {};

class WinBorder: public Border {};

class AbstractFactory {
public:
    virtual Button* CreateButton() =0;
    virtual Border* CreateBorder() =0;
};

class MacFactory: public AbstractFactory {
public:
    MacButton* CreateButton() { return new MacButton; }
    MacBorder* CreateBorder() { return new MacBorder; }
};

class WinFactory: public AbstractFactory {
public:
    WinButton* CreateButton() { return new WinButton; }
    WinBorder* CreateBorder() { return new WinBorder; }
};

AbstractFactory* fac;
switch (style) {
case MAC:
    fac = new MacFactory;
    break;
case WIN:
    fac = new WinFactory;
    break;
}
Button* button = fac->CreateButton();
Border* border = fac->CreateBorder();

1.4 abstract factory   drill

1.4.1 code

//  Step 1

// Create an interface for Shapes.

// Shape.java


public interface Shape {
   void draw();
}


// Step 2

// Create concrete classes implementing the same interface.

// Rectangle.java


public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}


// Square.java


public class Square implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}


// Circle.java


public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}


// Step 3

// Create an interface for Colors.

// Color.java


public interface Color {
   void fill();
}


// Step4

// Create concrete classes implementing the same interface.

// Red.java


public class Red implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Red::fill() method.");
   }
}




public class Green implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Green::fill() method.");
   }
}




public class Blue implements Color {

   @Override
   public void fill() {
      System.out.println("Inside Blue::fill() method.");
   }
}


// Step 5

// Create an Abstract class to get factories for Color and Shape Objects.

// AbstractFactory.java


public abstract class AbstractFactory {
   abstract Color getColor(String color);
   abstract Shape getShape(String shape) ;
}


// Step 6

// Create Factory classes extending AbstractFactory to generate object of
// concrete class based on given information.

// ShapeFactory.java


public class ShapeFactory extends AbstractFactory {

   @Override
   public Shape getShape(String shapeType){

      if(shapeType == null){
         return null;
      }

      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();

      }else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();

      }else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }

      return null;
   }

   @Override
   Color getColor(String color) {
      return null;
   }
}


// ColorFactory.java


public class ColorFactory extends AbstractFactory {

   @Override
   public Shape getShape(String shapeType){
      return null;
   }

   @Override
   Color getColor(String color) {

      if(color == null){
         return null;
      }

      if(color.equalsIgnoreCase("RED")){
         return new Red();

      }else if(color.equalsIgnoreCase("GREEN")){
         return new Green();

      }else if(color.equalsIgnoreCase("BLUE")){
         return new Blue();
      }

      return null;
   }
}


// Step 7

// Create a Factory generator/producer class to get factories by passing an information such as Shape or Color

// FactoryProducer.java


public class FactoryProducer {
   public static AbstractFactory getFactory(String choice){

      if(choice.equalsIgnoreCase("SHAPE")){
         return new ShapeFactory();

      }else if(choice.equalsIgnoreCase("COLOR")){
         return new ColorFactory();
      }

      return null;
   }
}


// Step 8

// Use the FactoryProducer to get AbstractFactory in order to get factories of
// concrete classes by passing an information such as type.

// AbstractFactoryPatternDemo.java


public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {

      //get shape factory
      AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");

      //get an object of Shape Circle
      Shape shape1 = shapeFactory.getShape("CIRCLE");

      //call draw method of Shape Circle
      shape1.draw();

      //get an object of Shape Rectangle
      Shape shape2 = shapeFactory.getShape("RECTANGLE");

      //call draw method of Shape Rectangle
      shape2.draw();

      //get an object of Shape Square
      Shape shape3 = shapeFactory.getShape("SQUARE");

      //call draw method of Shape Square
      shape3.draw();

      //get color factory
      AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");

      //get an object of Color Red
      Color color1 = colorFactory.getColor("RED");

      //call fill method of Red
      color1.fill();

      //get an object of Color Green
      Color color2 = colorFactory.getColor("Green");

      //call fill method of Green
      color2.fill();

      //get an object of Color Blue
      Color color3 = colorFactory.getColor("BLUE");

      //call fill method of Color Blue
      color3.fill();
   }
}


Step 9

Verify the output.


Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.

1.5 adapter   drill

Interface Bird 有兩個 function, fly() and makeSound(), 而 Toyduck 有一個
function, squeak(), adapter 的意思就是用一個 birdAdapter 有實作 toyduck 的
interface, 但是用餵入一個 bird 的方法去實作 toyDuck 的 interface


Object Adapter Vs Class Adapter

The adapter pattern we have implemented above is called Object Adapter Pattern because the adapter holds an instance of adaptee. There is also another type called Class Adapter Pattern which use inheritance instead of composition but you require multiple inheritance to implement it.

Class diagram of Class Adapter Pattern: pattern4

Here instead of having an adaptee object inside adapter (composition) to make use of its functionality adapter inherits the adaptee.

Since multiple inheritance is not supported by many languages including java and is associated with many problems we have not shown implementation using class adapter pattern.

Advantages:

  • Helps achieve reusability and flexibility.
  • Client class is not complicated by having to use a different interface and can use polymorphism to swap between different implementations of adapters.

    Disadvantages:

  • All requests are forwarded, so there is a slight increase in the overhead.
  • Sometimes many adaptations are required along an adapter chain to reach the type which is required.

1.5.1 code

interface Bird {
    public void fly();
    public void makeSound();
}

class Sparrow implements Bird {
    public void fly() {
        System.out.println("Flying");
    }
    public void makeSound() {
        System.out.println("Chirp Chirp");
    }
}

interface ToyDuck {
    public void squeak();
}

class PlasticToyDuck implements ToyDuck {
    public void squeak() {
        System.out.println("Squeak");
    }
}

class BirdAdapter implements ToyDuck {
    Bird bird;
    public BirdAdapter(Bird bird) {
        this.bird = bird;
    }

    public void squeak() {
        // translate the methods appropriately
        bird.makeSound();
    }
}

class Main {
    public static void main(String args[]) {
        Sparrow sparrow = new Sparrow();
        PlasticToyDuck toyDuck = new PlasticToyDuck();

        // xx adapter : change into another object -> toyDuck
        ToyDuck birdAdapter = new BirdAdapter(sparrow);

        System.out.println("Sparrow...");
        sparrow.fly();
        sparrow.makeSound();

        System.out.println("ToyDuck...");
        toyDuck.squeak();

        System.out.println("BirdAdapter...");
        birdAdapter.squeak();
    }
}


Output:

Sparrow...
Flying
Chirp Chirp
ToyDuck...
Squeak
BirdAdapter...
Chirp Chirp


1.6 builder   drill

  • note :

1.6.1 code

 interface HousePlan {
   public void setBasement(String basement);
   public void setStructure(String structure);
   public void setRoof(String roof);
   public void setInterior(String interior);
 }

 class House implements HousePlan {
   private String basement;
   private String structure;
   private String roof;
   private String interior;

   public void setBasement(String basement) {
     this.basement = basement;
   }

   public void setStructure(String structure) {
     this.structure = structure;
   }

   public void setRoof(String roof) {
     this.roof = roof;
   }

   public void setInterior(String interior) {
     this.interior = interior;
   }

 }

interface HouseBuilder {
   public void buildBasement();
   public void buildStructure();
   public void bulidRoof();
   public void buildInterior();
   public House getHouse();
 }

 class IglooHouseBuilder implements HouseBuilder {
   private House house;

   public IglooHouseBuilder() {
     this.house = new House();
   }

   public void buildBasement() {
     house.setBasement("Ice Bars");
   }

   public void buildStructure() {
     house.setStructure("Ice Blocks");
   }

   public void buildInterior() {
     house.setInterior("Ice Carvings");
   }

   public void bulidRoof() {
     house.setRoof("Ice Dome");
   }

   public House getHouse() {
     return this.house;
   }
 }

 class TipiHouseBuilder implements HouseBuilder {
   private House house;

   public TipiHouseBuilder() {
     this.house = new House();
   }

   public void buildBasement() {
     house.setBasement("Wooden Poles");
   }

   public void buildStructure() {
     house.setStructure("Wood and Ice");
   }

   public void buildInterior() {
     house.setInterior("Fire Wood");
   }

   public void bulidRoof() {
     house.setRoof("Wood, caribou and seal skins");
   }

   public House getHouse() {
     return this.house;
   }

 }
class CivilEngineer {

   private HouseBuilder houseBuilder;

   public CivilEngineer(HouseBuilder houseBuilder) {
     this.houseBuilder = houseBuilder;
   }

   public House getHouse() {
     return this.houseBuilder.getHouse();
   }

   public void constructHouse() {
     this.houseBuilder.buildBasement();
     this.houseBuilder.buildStructure();
     this.houseBuilder.bulidRoof();
     this.houseBuilder.buildInterior();
   }
 }
class Builder {public static void main(String[] args) {
     HouseBuilder iglooBuilder = new IglooHouseBuilder();
     CivilEngineer engineer = new CivilEngineer(iglooBuilder);

     engineer.constructHouse();
     House house = engineer.getHouse();

     System.out.println("Builder constructed: "+ house);
   }
 }


 Output :


 Builder constructed: House@6d06d69c
  * Adv
  - ctor 的 parameters 變少了,提供好讀的 function calls 
  - ctor 的 parameters 變少了,不用再傳 null 進去

builder : 
1) constructHouse : 準備原料
2) buildHouse : return 產品回去
3) ctor 的原料都在 construct 裡提供

1.7 builder : a abs class got some abs func to set up the materials   drill

  • note :

1.7.1 java

/** "Product" */
class Pizza {
  private String dough = "";
  private String sauce = "";
  private String topping = "";

  public void setDough (String dough)     { this.dough = dough; }
  public void setSauce (String sauce)     { this.sauce = sauce; }
  public void setTopping (String topping) { this.topping = topping; }
}


''/** "Abstract Builder" */''
abstract class pzBuilder{
  protected Pizza pizza;

  public Pizza getPizza() { return pizza; }
  public void createNewPizzaProduct() { pizza = new Pizza(); }

  public abstract void buildDough();
  public abstract void buildSauce();
  public abstract void buildTopping();
}

/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends pzBuilder{
  public void buildDough()   { pizza.setDough("cross"); }
  public void buildSauce()   { pizza.setSauce("mild"); }
  public void buildTopping() { pizza.setTopping("ham+pineapple"); }
}

/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends pzBuilder{
  public void buildDough()   { pizza.setDough("pan baked"); }
  public void buildSauce()   { pizza.setSauce("hot"); }
  public void buildTopping() { pizza.setTopping("pepperoni+salami"); }
}


class Waiter {
  private pzBuilderpizzaBuilder;

  public void setBuilder(pzBuilderpb) { pbBuilder= pb; }
  public Pizza getPizza() { return pbBuilder.getPizza(); }

  public void genPizza() {
    pbBuilder.createNewPizzaProduct();
    pbBuilder.buildDough();
    pbBuilder.buildSauce();
    pbBuilder.buildTopping();
  }
}

/** A customer ordering a pizza. */
// 1. waiter 來決定他要拿哪一個 builder, spicy or hawaiian
// 2. waiter 不用管怎麼把原料準備好,而是由 builder 的 implementation 決定 
// 3. waiter 只要直接 build(), 就可以生成 spice or hawaiian pizza
// 4. 需要 waiter, 和他的 ctor parameters, concretebuilder 
// 5. spicy-pz-builder and hawaiian-pz-builder 
class BuilderExample {
  public static void main(String[] args) {
    Waiter waiter = new Waiter();
    pzBuilderhawaiian_pizzabuilder = new HawaiianPizzaBuilder();
    pzBuilderspicy_pizzabuilder = new SpicyPizzaBuilder();

    waiter.setBuilder( hawaiian_pizzabuilder );
    waiter.genPizza();

    Pizza pizza = waiter.getPizza();
  }
}

1.8 builder   drill

  • note :

1.8.1 code

public interface Item {
   public String name();
   public Packing packing();
   public float price();
}


Packing.java


public interface Packing {
   public String pack();
}



public class Wrapper implements Packing {

   @Override
   public String pack() {
      return "Wrapper";
   }
}


Bottle.java


public class Bottle implements Packing {

   @Override
   public String pack() {
      return "Bottle";
   }
}


Step 3

Create abstract classes implementing the item interface providing default functionalities.

Burger.java


public abstract class Burger implements Item {

   @Override
   public Packing packing() {
      return new Wrapper();
   }

   @Override
   public abstract float price();
}


ColdDrink.java


public abstract class ColdDrink implements Item {

  @Override
  public Packing packing() {
       return new Bottle();
  }

  @Override
  public abstract float price();
}


Step 4

Create concrete classes extending Burger and ColdDrink classes

VegBurger.java


public class VegBurger extends Burger {

   @Override
   public float price() {
      return 25.0f;
   }

   @Override
   public String name() {
      return "Veg Burger";
   }
}


ChickenBurger.java


public class ChickenBurger extends Burger {

   @Override
   public float price() {
      return 50.5f;
   }

   @Override
   public String name() {
      return "Chicken Burger";
   }
}


Coke.java


public class Coke extends ColdDrink {

   @Override
   public float price() {
      return 30.0f;
   }

   @Override
   public String name() {
      return "Coke";
   }
}


Pepsi.java


public class Pepsi extends ColdDrink {

   @Override
   public float price() {
      return 35.0f;
   }

   @Override
   public String name() {
      return "Pepsi";
   }
}


Step 5

Create a Meal class having Item objects defined above.

Meal.java


import java.util.ArrayList;
import java.util.List;

public class Meal {
   private List<Item> items = new ArrayList<Item>();

   public void addItem(Item item){
      items.add(item);
   }

   public float getCost(){
      float cost = 0.0f;

      for (Item item : items) {
         cost += item.price();
      }
      return cost;
   }

   public void showItems(){

      for (Item item : items) {
         System.out.print("Item : " + item.name());
         System.out.print(", Packing : " + item.packing().pack());
         System.out.println(", Price : " + item.price());
      }
   }
}


Step 6

Create a MealBuilder class, the actual builder class responsible to create Meal objects.

MealBuilder.java


public class MealBuilder {

   public Meal prepareVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new VegBurger());
      meal.addItem(new Coke());
      return meal;
   }

   public Meal prepareNonVegMeal (){
      Meal meal = new Meal();
      meal.addItem(new ChickenBurger());
      meal.addItem(new Pepsi());
      return meal;
   }
}


Step 7

BuiderPatternDemo uses MealBuider to demonstrate builder pattern.

BuilderPatternDemo.java


public class BuilderPatternDemo {
   public static void main(String[] args) {

      MealBuilder mealBuilder = new MealBuilder();

      Meal vegMeal = mealBuilder.prepareVegMeal();
      System.out.println("Veg Meal");
      vegMeal.showItems();
      System.out.println("Total Cost: " + vegMeal.getCost());

      Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
      System.out.println("\n\nNon-Veg Meal");
      nonVegMeal.showItems();
      System.out.println("Total Cost: " + nonVegMeal.getCost());
   }
}


Step 8

Verify the output.


Veg Meal
Item : Veg Burger, Packing : Wrapper, Price : 25.0
Item : Coke, Packing : Bottle, Price : 30.0
Total Cost: 55.0


Non-Veg Meal
Item : Chicken Burger, Packing : Wrapper, Price : 50.5
Item : Pepsi, Packing : Bottle, Price : 35.0
Total Cost: 85.5

1.9 observer pattern

Step 1
Create Subject class.

Subject.java
// 1. 目標有一串 observers
// 2. 目標負責增加/去除 observer
// 3. 目標負責設定狀態
// 4. 目標負責通知 observers
// 4.1 通知的方法,就是去 call 每一個 observer 的 update function
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
// 1. observer 的必要條件 
// 2. abstract update function 
// 3. 存一個 subject 
// 4. 在 observer 的 ctor 之中,用傳入的 subject 來新增一個 observer


public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}
Step 3
Create concrete observer classes

BinaryObserver.java

public class BinaryObserver extends Observer{

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

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

public class OctalObserver extends Observer{

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

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

public class HexaObserver extends Observer{

   public HexaObserver(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.

ObserverPatternDemo.java

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

      new HexaObserver(subject);
      new OctalObserver(subject);
      new BinaryObserver(subject);

      System.out.println("First state change: 15"); 
      subject.setState(15);
      System.out.println("Second state change: 10");  
      subject.setState(10);
   }
}
Step 5
Verify the output.

First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010

1.10 chain of responsibility   drill

  • note :

1.10.1 code

interface Chain {
  public abstract void setNext(Chain nextInChain);
  public abstract void process(Number request);
}

class Number {
  private int number;

  public Number(int number) {
    this.number = number;
  }

  public int getNumber() {
    return number;
  }

}

class NegativeProcessor implements Chain {
  private Chain nextInChain;

  public void setNext(Chain c) {
    nextInChain = c;
  }

  public void process(Number request) {
    if (request.getNumber() < 0) {
      System.out.println("NegativeProcessor : " + request.getNumber());
    }
    else {
      nextInChain.process(request);
    }
  }
}

class ZeroProcessor implements Chain {

  private Chain nextInChain;

  public void setNext(Chain c) {
    nextInChain = c;
  }

  public void process(Number request) {
    if (request.getNumber() == 0) {
      System.out.println("ZeroProcessor : " + request.getNumber());
    }
    else {
      nextInChain.process(request);
    }
  }
}

class PositiveProcessor implements Chain {

  private Chain nextInChain;

  public void setNext(Chain c) {
    nextInChain = c;
  }

  public void process(Number request) {
    if (request.getNumber() > 0) {
      System.out.println("PositiveProcessor : " + request.getNumber());
    }
    else {
      nextInChain.process(request);
    }
  }
}

class TestChain {public static void main(String[] args) {
    //configure Chain of Responsibility
    Chain c1 = new NegativeProcessor();
    Chain c2 = new ZeroProcessor();
    Chain c3 = new PositiveProcessor();
    c1.setNext(c2);
    c2.setNext(c3);

    //calling chain of responsibility
    c1.process(new Number(90));
    c1.process(new Number(-50));
    c1.process(new Number(0));
    c1.process(new Number(91));
  }
}


Output :


PositiveProcessor : 90
NegativeProcessor : -50
ZeroProcessor : 0
PositiveProcessor : 91


* Adv
-  To reduce the coupling degree. Decoupling it will request the sender and receiver.
-  Simplified object. The object does not need to know the chain structure.
- Enhance flexibility of object assigned duties. By changing the members within
  the chain or change their order, allow dynamic adding or deleting
  responsibility.
-  Increase the request processing new class of very convenient.

* disAdv

- The request must be received not guarantee.
- The performance of the system will be affected, but also in the code debugging is not easy may cause cycle call.
- It may not be easy to observe the characteristics of operation, due to debug.

1.11 command pattern   drill

  • note :

1.11.1 code

/*
1. remote control only receive commands
2. command need a subject
3. command examples : lightOn, lightOff, StereoPlay, StereoStop
4. remote control, button pressed
 */
interface Command {
     public void execute();
 }

 class Light {
     public void on() {
         System.out.println("Light is on");
     }
     public void off() {
         System.out.println("Light is off");
     }
 }
 class LightOnCommand implements Command {
     Light light;
     public LightOnCommand(Light light) {
        this.light = light;
     }
     public void execute() {
        light.on();
     }
 }
 class LightOffCommand implements Command {
     Light light;
     public LightOffCommand(Light light) {
         this.light = light;
     }
     public void execute() {
          light.off();
     }
 }
 class Stereo {
     public void on() {
         System.out.println("Stereo is on");
     }
     public void off() {
         System.out.println("Stereo is off");
     }
     public void setCD() {
         System.out.println("Stereo is set " + "for CD input");
     }
     public void setDVD() {
         System.out.println("Stereo is set"+ " for DVD input");
     }
     public void setRadio() {
         System.out.println("Stereo is set" + " for Radio");
     }
     public void setVolume(int volume) {
        System.out.println("Stereo volume set" + " to " + volume);
     }
 }
 class StereoOffCommand implements Command {
     Stereo stereo;
     public StereoOffCommand(Stereo stereo) {
         this.stereo = stereo;
     }
     public void execute() {
        stereo.off();
     }
 }
 class StereoOnWithCDCommand implements Command {
      Stereo stereo;
      public StereoOnWithCDCommand(Stereo stereo) {
          this.stereo = stereo;
      }
      public void execute() {
          stereo.on();
          stereo.setCD();
          stereo.setVolume(11);
      }
 }
 class SimpleRemoteControl {
     Command slot;  // only one button
     public SimpleRemoteControl() {}
     public void setCommand(Command command) {
         slot = command;
     }

     public void buttonWasPressed() {
         slot.execute();
     }
 }

 class RemoteControlTest {
     public static void main(String[] args) {
         SimpleRemoteControl remote = new SimpleRemoteControl();
         Light light = new Light();
         Stereo stereo = new Stereo();
         // we can change command dynamically
         remote.setCommand(new LightOnCommand(light));
         remote.buttonWasPressed();
         remote.setCommand(new StereoOnWithCDCommand(stereo));
         remote.buttonWasPressed();
         remote.setCommand(new StereoOffCommand(stereo));
         remote.buttonWasPressed();
      }
   }


 Output:

 Light is on
 Stereo is on
 Stereo is set for CD input
 Stereo volume set to 11
 Stereo is off


 Notice that the remote control doesn’t know anything about turning on the
 stereo. That information is contained in a separate command object. This
 reduces the coupling between them.

 Advantages:

** Makes our code extensible as we can add new commands without changing existing code.
** Reduces coupling the invoker and receiver of a command.

 Disadvantages:

** Increase in the number of classes for each individual command

1.12 CRTP   drill

1.12.1 code

Curiously Recurring Template Pattern
(CRTP)
1. avoid Usage of VPtr and VTable can be avoided altogether
2. a class X derives from a class template instantiation using X itself as template argument.

3. known as F-bound polymorphism.


// Image program (similar to above) to demonstrate
// working of CRTP
#include <iostream>
#include <chrono>
using namespace std;

typedef std::chrono::high_resolution_clock Clock;

// To store dimensions of an image
class Dimension
{
public:
    Dimension(int _X, int _Y)
    {
        mX = _X;
        mY = _Y;
    }
private:
    int mX, mY;
};

// Base class for all image types. The template
// parameter T is used to know type of derived
// class pointed by pointer.
template <class T>
class Image
{
public:
    void Draw()
    {
        // Dispatch call to exact type
        static_cast<T*> (this)->Draw();
    }
    Dimension GetDimensionInPixels()
    {
        // Dispatch call to exact type
        static_cast<T*> (this)->GetDimensionInPixels();
    }

protected:
    int dimensionX, dimensionY;
};


// For Tiff Images
class TiffImage : public Image<TiffImage>
{
public:
    void Draw()
    {
        // Uncomment this to check method dispatch
        // cout << "TiffImage::Draw() called" << endl;
    }
    Dimension GetDimensionInPixels()
    {
        return Dimension(dimensionX, dimensionY);
    }
};

// There can be more derived classes like PngImage,
// BitmapImage, etc

// Driver code
int main()
{
    // An Image type pointer pointing to Tiffimage
    Image<TiffImage>* pImage = new TiffImage;

    // Store time before virtual function calls
    auto then = Clock::now();

    // Call Draw 1000 times to make sure performance
    // is visible
    for (int i = 0; i < 1000; ++i)
        pImage->Draw();

    // Store time after virtual function calls
    auto now = Clock::now();

    cout << "Time taken: "
         << std::chrono::duration_cast
         <std::chrono::nanoseconds>(now - then).count()
         << " nanoseconds" << endl;

    return 0;
}


Output :

Time taken: 732 nanoseconds


See this for above result.

Virtual method vs CRTP benchmark
The time taken while using virtual method was 2613 nanoseconds. This (small)
performance gain from CRTP is because the use of a VTable dispatch has been
circumvented. Please note that the performance depends on a lot of factors like
compiler used, operations performed by virtual methods. Performance numbers
might differ in different runs, but (small) performance gain is expected from
CRTP. Note: If we print size of class in CRTP, it can bee seen that VPtr no
longer reserves 4 bytes of memory.


cout )

1.13 decorator: keep a abstract as a member and this is also this type   drill

  • note :

1.13.1 cpp

#include <iostream>

using namespace std;

class Widget {
public:
  virtual void draw() = 0;
  virtual ~Widget() {}
};

class TextField : public Widget {
private:
  int width, height;

public:
  TextField( int w, int h ){
    width  = w;
    height = h;
  }

  void draw() {
    cout << "TextField: " << width << ", " << height << '\n';
  }
};

class Decorator : public Widget {
private:
  Widget* wid;       // reference to Widget

public:
  Decorator( Widget* w )  {
    wid = w;
  }

  void draw() {
    wid->draw();
  }

  ~Decorator() {
    delete wid;
  }
};

class BorderDecorator : public Decorator {
public:
  BorderDecorator( Widget* w ) : Decorator( w ) { }
  void draw() {
    Decorator::draw();
    cout << "   BorderDecorator" << '\n';
  }
};

class ScrollDecorator : public Decorator {
public:
  ScrollDecorator( Widget* w ) : Decorator( w ) { }
  void draw() {
    Decorator::draw();
    cout << "   ScrollDecorator" << '\n';
  }
};

int main( void ) {

  Widget* aWidget = new BorderDecorator(new BorderDecorator(new ScrollDecorator(new TextField( 80, 24 ))));
  aWidget->draw();
  delete aWidget;
}
// TextField: 80, 24
//             ScrollDecorator
//             BorderDecorator
//             BorderDecorator

1.13.2 code

// The Window interface class
public interface Window {
    public void draw(); // Draws the Window
    public String getDescription(); // Returns a description of the Window
}


// implementation of a simple Window without any scrollbars
public class SimpleWindow implements Window {
    public void draw() {
        // Draw window
    }

    public String getDescription() {
        return "simple window";
    }
}
// abstract decorator class - note that it implements Window
public abstract class WindowDecorator implements Window {
    protected Window decoratedWindow; // the Window being decorated

    public WindowDecorator (Window decoratedWindow) {
        this.decoratedWindow = decoratedWindow;
    }

    @Override
    public void draw() {
        decoratedWindow.draw();
    }

    @Override
    public String getDescription() {
        return decoratedWindow.getDescription();
    }
}


// The first concrete decorator which adds vertical scrollbar functionality
public class VerticalScrollBar extends WindowDecorator {
    public VerticalScrollBar(Window windowToBeDecorated) {
        super(windowToBeDecorated);
    }

    @Override
    public void draw() {
        super.draw();
        drawVerticalScrollBar();
    }

    private void drawVerticalScrollBar() {
        // Draw the vertical scrollbar
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", including vertical scrollbars";
    }
}


// The second concrete decorator which adds horizontal scrollbar functionality
public class HorizontalScrollBar extends WindowDecorator {
    public HorizontalScrollBar (Window windowToBeDecorated) {
        super(windowToBeDecorated);
    }

    @Override
    public void draw() {
        super.draw();
        drawHorizontalScrollBar();
    }

    private void drawHorizontalScrollBar() {
        // Draw the horizontal scrollbar
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", including horizontal scrollbars";
    }
}
//以下是一個測試程序,它創建了一個包含多重裝飾的Window實例(如,包含了垂直的和水平的滾動條),然後輸出它的描述:
public class Main {
    // for print descriptions of the window subclasses
    static void printInfo(Window w) {
        System.out.println("description:"+w.getDescription());
    }
    public static void main(String[] args) {
        // original SimpleWindow
        SimpleWindow sw = new SimpleWindow();
        printInfo(sw);
        // HorizontalScrollBar  mixed Window
        HorizontalScrollBar hbw = new HorizontalScrollBar(sw);
        printInfo(hbw);
        // VerticalScrollBar mixed Window
        VerticalScrollBar vbw = new VerticalScrollBar(hbw);
        printInfo(vbw);
    }
}
/*
  以下是SimpleWindow及添加了組件HorizontalScrollBar和VerticalScrollBar後的Window測試結果:
  description:simple window
  description:simple window, including horizontal scrollbars
  description:simple window, including horizontal scrollbars, including vertical scrollbars

*/

1.14 flyweight   drill

  • note :

1.14.1 code

import java.util.Random;
import java.util.HashMap;
interface Player {
    public void assignWeapon(String weapon);
    public void mission();
}

class Terrorist implements Player {
    private final String TASK;

    private String weapon;
    public Terrorist() {
        TASK = "PLANT A BOMB";
    }
    public void assignWeapon(String weapon) {
        this.weapon = weapon;
    }
    public void mission() {
        System.out.println("Terrorist with weapon " + weapon + "|" + " Task is " + TASK);
    }
}

class CounterTerrorist implements Player {
    private final String TASK;

    private String weapon;
    public CounterTerrorist() {
        TASK = "DIFFUSE BOMB";
    }
    public void assignWeapon(String weapon) {
        this.weapon = weapon;
    }
    public void mission() {
        System.out.println("Counter Terrorist with weapon " + weapon + "|" + " Task is " + TASK);
    }
}
  class PlayerFactory{
    private static HashMap <String, Player> hm = new HashMap<String, Player>();
    public static Player getPlayer(String type) {
        Player p = null;
        if (hm.containsKey(type))
                p = hm.get(type);
        else {
            switch(type) {
            case "Terrorist":
                System.out.println("Terrorist Created");
                p = new Terrorist();
                break;
            case "CounterTerrorist":
                System.out.println("Counter Terrorist Created");
                p = new CounterTerrorist();
                break;
            default :
                System.out.println("Unreachable code!");
            }

            hm.put(type, p);
        }
        return p;
    }
}

public class CounterStrike {
    private static String[] playerType = {"Terrorist", "CounterTerrorist"};
    private static String[] weapons = {"AK-47", "Maverick", "Gut Knife", "Desert Eagle"};


    public static void main(String args[]) {
        /* Assume that we have a total of 10 players
           in the game. */
        for (int i = 0; i < 10; i++) {
            /* getPlayer() is called simply using the class
               name since the method is a static one */
            Player p = PlayerFactory.getPlayer(getRandPlayerType());
            /* Assign a weapon chosen randomly uniformly
               from the weapon array  */
            p.assignWeapon(getRandWeapon());
            p.mission();
        }
    }
    public static String getRandPlayerType() {
        Random r = new Random();
        int randInt = r.nextInt(playerType.length);
        return playerType[randInt];
    }
    public static String getRandWeapon() {
        Random r = new Random();
        int randInt = r.nextInt(weapons.length);
        return weapons[randInt];
    }
}

Output:
Counter Terrorist Created
Counter Terrorist with weapon Gut Knife| Task is DIFFUSE BOMB
Counter Terrorist with weapon Desert Eagle| Task is DIFFUSE BOMB
Terrorist Created
Terrorist with weapon AK-47| Task is PLANT A BOMB
Terrorist with weapon Gut Knife| Task is PLANT A BOMB
Terrorist with weapon Gut Knife| Task is PLANT A BOMB
Terrorist with weapon Desert Eagle| Task is PLANT A BOMB
Terrorist with weapon AK-47| Task is PLANT A BOMB
Counter Terrorist with weapon Desert Eagle| Task is DIFFUSE BOMB
Counter Terrorist with weapon Gut Knife| Task is DIFFUSE BOMB
Counter Terrorist with weapon Desert Eagle| Task is DIFFUSE BOMB

1.15 itearator   drill

1.15.1 code

class Notification {
    // To store notification message
    String notification;

    public Notification(String notification) {
        this.notification = notification;
    }
    public String getNotification() {
        return notification;
    }
}

// Collection interface
interface Collection {
    public Iterator createIterator();
}

// Collection of notifications
class NotificationCollection implements Collection {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    Notification[] notificationList;

    public NotificationCollection() {
        notificationList = new Notification[MAX_ITEMS];

        // Let us add some dummy notifications
        addItem("Notification 1");
        addItem("Notification 2");
        addItem("Notification 3");
    }

    public void addItem(String str) {
        Notification notification = new Notification(str);
        if (numberOfItems >= MAX_ITEMS)
            System.err.println("Full");
        else {
            notificationList[numberOfItems] = notification;
            numberOfItems = numberOfItems + 1;
        }
    }

    public Iterator createIterator() {
        return new NotificationIterator(notificationList);
    }
}

// We could also use Java.Util.Iterator
interface Iterator {
    // indicates whether there are more elements to
    // iterate over
    boolean hasNext();

    // returns the next element
    Object next();
}

// Notification iterator
class NotificationIterator implements Iterator {
    Notification[] notificationList;

    // maintains curr pos of iterator over the array
    int pos = 0;

    // Constructor takes the array of notifiactionList are
    // going to iterate over.
    public  NotificationIterator (Notification[] notificationList) {
        this.notificationList = notificationList;
    }

    public Object next() {
        // return next element in the array and increment pos
        Notification notification =  notificationList[pos];
        pos += 1;
        return notification;
    }

    public boolean hasNext() {
        if (pos >= notificationList.length ||
            notificationList[pos] == null)
            return false;
        else
            return true;
    }
}

// Contains collection of notifications as an object of
// NotificationCollection
class NotificationBar {
    NotificationCollection notifications;

    public NotificationBar(NotificationCollection notifications) {
        this.notifications = notifications;
    }

    public void printNotifications() {
        Iterator iterator = notifications.createIterator();
        System.out.println("-------NOTIFICATION BAR------------");
        while (iterator.hasNext()) {
            Notification n = (Notification)iterator.next();
            System.out.println(n.getNotification());
        }
    }
}

// Driver class
class Main {
    public static void main(String args[]) {
        NotificationCollection nc = new NotificationCollection();
        NotificationBar nb = new NotificationBar(nc);
        nb.printNotifications();
    }
}


Output:

-------NOTIFICATION BAR------------
Notification 1
Notification 2
Notification 3

1.16 object pool   drill

1.16.1 code


The object pool pattern is a software creational design pattern that uses a set
of initialized objects kept ready to use – a "pool" – rather than allocating and
destroying them on demand. A client of the pool will request an object from the
pool and perform operations on the returned object. When the client has
finished, it returns the object to the pool rather than destroying it; this can
be done manually or automatically.

Object pools are primarily used for performance: in some circumstances, object
pools significantly improve performance. Object pools complicate object
lifetime, as objects obtained from and returned to a pool are not actually
created or destroyed at this time, and thus require care in implementation.
 // ObjectPool Class

public abstract class ObjectPool<T> {
  private long expirationTime;

  private Hashtable<T, Long> locked, unlocked;

  public ObjectPool() {
    expirationTime = 30000; // 30 seconds
    locked = new Hashtable<T, Long>();
    unlocked = new Hashtable<T, Long>();
  }

  protected abstract T create();

  public abstract boolean validate(T o);

  public abstract void expire(T o);

  public synchronized T checkOut() {
    long now = System.currentTimeMillis();
    T t;
    if (unlocked.size() > 0) {
      Enumeration<T> e = unlocked.keys();
      while (e.hasMoreElements()) {
        t = e.nextElement();
        if ((now - unlocked.get(t)) > expirationTime) {
          // object has expired
          unlocked.remove(t);
          expire(t);
          t = null;
        } else {
          if (validate(t)) {
            unlocked.remove(t);
            locked.put(t, now);
            return (t);
          } else {
            // object failed validation
            unlocked.remove(t);
            expire(t);
            t = null;
          }
        }
      }
    }
    // no objects available, create a new one
    t = create();
    locked.put(t, now);
    return (t);
  }

  public synchronized void checkIn(T t) {
    locked.remove(t);
    unlocked.put(t, System.currentTimeMillis());
  }
}

//The three remaining methods are abstract 
//and therefore must be implemented by the subclass

public class JDBCConnectionPool extends ObjectPool<Connection> {

  private String dsn, usr, pwd;

  public JDBCConnectionPool(String driver, String dsn, String usr, String pwd) {
    super();
    try {
      Class.forName(driver).newInstance();
    } catch (Exception e) {
      e.printStackTrace();
    }
    this.dsn = dsn;
    this.usr = usr;
    this.pwd = pwd;
  }

  @Override
  protected Connection create() {
    try {
      return (DriverManager.getConnection(dsn, usr, pwd));
    } catch (SQLException e) {
      e.printStackTrace();
      return (null);
    }
  }

  @Override
  public void expire(Connection o) {
    try {
      ((Connection) o).close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

  @Override
  public boolean validate(Connection o) {
    try {
      return (!((Connection) o).isClosed());
    } catch (SQLException e) {
      e.printStackTrace();
      return (false);
    }
  }
}

JDBCConnectionPool will allow the application to borrow and return database connections:


public class Main {
  public static void main(String args[]) {
    // Do something...
    ...

    // Create the ConnectionPool:
    JDBCConnectionPool pool = new JDBCConnectionPool(
      "org.hsqldb.jdbcDriver", "jdbc:hsqldb://localhost/mydb",
      "sa", "secret");

    // Get a connection:
    Connection con = pool.checkOut();

    // Use the connection
    ...

    // Return the connection:
    pool.checkIn(con);

  }
}

public class PooledObject {
  public String temp1;
  public String temp2;
  public String temp3;

  public String getTemp1() {
    return temp1;
  }
  public void setTemp1(String temp1) {
    this.temp1 = temp1;
  }
  public String getTemp2() {
    return temp2;
  }
  public void setTemp2(String temp2) {
    this.temp2 = temp2;
  }
  public String getTemp3() {
    return temp3;
  }
  public void setTemp3(String temp3) {
    this.temp3 = temp3;
  }



}

public class PooledObjectPool {
  private static long expTime = 60000;//6 seconds
  public static HashMap<PooledObject, Long> available = new HashMap<PooledObject, Long>();
  public static HashMap<PooledObject, Long> inUse = new HashMap<PooledObject, Long>();


  public synchronized static PooledObject getObject() {
    long now = System.currentTimeMillis();
    if (!available.isEmpty()) {
      for (Map.Entry<PooledObject, Long> entry : available.entrySet()) {
        if (now - entry.getValue() > expTime) { //object has expired
          popElement(available);
        } else {
          PooledObject po = popElement(available, entry.getKey());
          push(inUse, po, now);
          return po;
        }
      }
    }

    // either no PooledObject is available or each has expired, so return a new one
    return createPooledObject(now);
  }

  private synchronized static PooledObject createPooledObject(long now) {
    PooledObject po = new PooledObject();
    push(inUse, po, now);
    return po;
        }

  private synchronized static void push(HashMap<PooledObject, Long> map,
      PooledObject po, long now) {
    map.put(po, now);
  }

  public static void releaseObject(PooledObject po) {
    cleanUp(po);
    available.put(po, System.currentTimeMillis());
    inUse.remove(po);
  }

  private static PooledObject popElement(HashMap<PooledObject, Long> map) {
     Map.Entry<PooledObject, Long> entry = map.entrySet().iterator().next();
     PooledObject key= entry.getKey();
     //Long value=entry.getValue();
     map.remove(entry.getKey());
     return key;
  }

  private static PooledObject popElement(HashMap<PooledObject, Long> map, PooledObject key) {
    map.remove(key);
    return key;
  }

  public static void cleanUp(PooledObject po) {
    po.setTemp1(null);
    po.setTemp2(null);
    po.setTemp3(null);
  }
}

1.17 polymorphism   drill

  • note :

1.17.1 code

#include <iostream>
#include <chrono>
using namespace std;

typedef std::chrono::high_resolution_clock Clock;

// To store dimensions of an image
class Dimension {
public:
    Dimension(int X, int Y) {mX = X;  mY = Y; }
private:
    int mX, mY;
};

// Base class for all image types
class Image {
public:
    virtual void Draw() = 0;
    virtual Dimension GetDimensionInPixels() = 0;
protected:
    int dimensionX;
    int dimensionY;
};

// For Tiff Images
class TiffImage : public Image
{
public:
    void Draw() { }
    Dimension GetDimensionInPixels() {
        return Dimension(dimensionX, dimensionY);
    }
};

// There can be more derived classes like PngImage,
// BitmapImage, etc

// Driver code that calls virtual function
int main()
{
    // An image type
    Image* pImage = new TiffImage;

    // Store time before virtual function calls
    auto then = Clock::now();

    // Call Draw 1000 times to make sure performance
    // is visible
    for (int i = 0; i < 1000; ++i)
        pImage->Draw();

    // Store time after virtual function calls
    auto now = Clock::now();

    cout << "Time taken: "
         << std::chrono::duration_cast
           <std::chrono::nanoseconds>(now - then).count()
         << " nanoseconds" << endl;

    return 0;
}


Output :
Time taken: 2613 nanoseconds

1.18 prototype   drill

  • note :

1.18.1 java

/** Prototype Class **/
public class Cookie implements Cloneable {

   public Object clone() throws CloneNotSupportedException
   {
       //In an actual implementation of this pattern you would now attach references to
       //the expensive to produce parts from the copies that are held inside the prototype.
       return (Cookie) super.clone();
   }
}

/** Concrete Prototypes to clone **/
public class CoconutCookie extends Cookie { }

/** Client Class**/
public class CookieMachine
{

  private Cookie cookie;//cookie必须是可复制的

    public CookieMachine(Cookie cookie) { 
        this.cookie = cookie; 
    } 

   public Cookie makeCookie()
   {
       try
       {
           return (Cookie) cookie.clone();
       } catch (CloneNotSupportedException e)
       {
           e.printStackTrace();
       }
       return null;
   } 


    public static void main(String args[]){ 
        Cookie tempCookie =  null; 
        Cookie prot = new CoconutCookie(); 
        CookieMachine cm = new CookieMachine(prot); //设置原型
        for(int i=0; i<100; i++) 
            tempCookie = cm.makeCookie();//通过复制原型返回多个cookie 
    } 
}

1.18.2 code

#include <iostream>

enum imageType
{
  LSAT, SPOT
};

class Image
{
  public:
    virtual void draw() = 0;
    static Image *findAndClone(imageType);
  protected:
    virtual imageType returnType() = 0;
    virtual Image *clone() = 0;
    // As each subclass of Image is declared, it registers its prototype
    static void addPrototype(Image *image)
    {
        _prototypes[_nextSlot++] = image;
    }
  private:
    // addPrototype() saves each registered prototype here
    static Image *_prototypes[10];
    static int _nextSlot;
};

Image *Image::_prototypes[];
int Image::_nextSlot;

// Client calls this public static member function when it needs an instance
// of an Image subclass
Image *Image::findAndClone(imageType type) {
  for (int i = 0; i < _nextSlot; i++)
    if (_prototypes[i]->returnType() == type)
      return _prototypes[i]->clone();
  return NULL;
}

class LandSatImage: public Image {
  public:
    imageType returnType() {
        return LSAT;
    }
    void draw() {
        std::cout << "LandSatImage::draw " << _id << std::endl;
    }
    // When clone() is called, call the one-argument ctor with a dummy arg
    Image *clone() {
        return new LandSatImage(1);
    }
  protected:
    // This is only called from clone()
    LandSatImage(int dummy) {
        _id = _count++;
    }
  private:
    // Mechanism for initializing an Image subclass - this causes the
    // default ctor to be called, which registers the subclass's prototype
    static LandSatImage _landSatImage;
    // This is only called when the private static data member is initiated
    LandSatImage()
    {
        addPrototype(this);
    }
    // Nominal "state" per instance mechanism
    int _id;
    static int _count;
};

// Register the subclass's prototype
LandSatImage LandSatImage::_landSatImage;
// Initialize the "state" per instance mechanism
int LandSatImage::_count = 1;

class SpotImage: public Image
{
  public:
    imageType returnType()
    {
        return SPOT;
    }
    void draw()
    {
        std::cout << "SpotImage::draw " << _id << std::endl;
    }
    Image *clone()
    {
        return new SpotImage(1);
    }
  protected:
    SpotImage(int dummy)
    {
        _id = _count++;
    }
  private:
    SpotImage()
    {
        addPrototype(this);
    }
    static SpotImage _spotImage;
    int _id;
    static int _count;
};

SpotImage SpotImage::_spotImage;
int SpotImage::_count = 1;

// Simulated stream of creation requests
const int NUM_IMAGES = 8;
imageType input[NUM_IMAGES] =
{
  LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT
};

int main()
{
  Image *images[NUM_IMAGES];

  // Given an image type, find the right prototype, and return a clone
  for (int i = 0; i < NUM_IMAGES; i++)
    images[i] = Image::findAndClone(input[i]);

  // Demonstrate that correct image objects have been cloned
  for (int i = 0; i < NUM_IMAGES; i++)
    images[i]->draw();

  // Free the dynamic memory
  for (int i = 0; i < NUM_IMAGES; i++)
    delete images[i];
}


Output


LandSatImage::draw 1
LandSatImage::draw 2
LandSatImage::draw 3
SpotImage::draw 1
LandSatImage::draw 4
SpotImage::draw 2
SpotImage::draw 3
LandSatImage::draw 5

1.19 prototype in java   drill

  • note :

1.19.1 code

 // A Java program to demonstrate working of
// Prototype Design Pattern with example
// of a ColorStore class to store existing objects.

import java.util.HashMap;
import java.util.Map;


abstract class Color implements Cloneable
{

    protected String colorName;

    abstract void addColor();

    public Object clone()
    {
        Object clone = null;
        try
        {
            clone = super.clone();
        }
        catch (CloneNotSupportedException e)
        {
            e.printStackTrace();
        }
        return clone;
    }
}

class blueColor extends Color
{
    public blueColor()
    {
        this.colorName = "blue";
    }

    @Override
    void addColor()
    {
        System.out.println("Blue color added");
    }

}

class blackColor extends Color{

    public blackColor()
    {
        this.colorName = "black";
    }

    @Override
    void addColor()
    {
        System.out.println("Black color added");
    }
}

class ColorStore {

    private static Map<String, Color> colorMap = new HashMap<String, Color>();

    static
    {
        colorMap.put("blue", new blueColor());
        colorMap.put("black", new blackColor());
    }

    public static Color getColor(String colorName)
    {
        return (Color) colorMap.get(colorName).clone();
    }
}


// Driver class
class Prototype
{
    public static void main (String[] args)
    {
        ColorStore.getColor("blue").addColor();
        ColorStore.getColor("black").addColor();
        ColorStore.getColor("black").addColor();
        ColorStore.getColor("blue").addColor();
    }
}



Output :


Blue color added
Black color added
Black color added
Blue color added

1.20 virtual   drill

  • note :

1.20.1 code

 When a method is declared virtual, compiler secretly does two things for us:

1. Defines a VPtr in first 4 bytes of the class object
2. Inserts code in constructor to initialize VPtr to point to the VTable

What are VTable and VPtr?

When a method is declared virtual in a class, 
1. compiler creates a virtual table (aka VTable) 
2. stores addresses of virtual methods in that table. 

A virtual pointer (aka VPtr) is then created and initialized to point to that
VTable. A VTable is shared across all the instances of the class, i.e. compiler
creates only one instance of VTable to be shared across all the objects of a
class. Each instance of the class has its own version of VPtr. If we print the
size of a class object containing at least one virtual method, the output will
be sizeof(class data) + sizeof(VPtr). Since address of virtual method is stored
in VTable, VPtr can be manipulated to make calls to those virtual methods
thereby violating principles of encapsulation. See below example:


#include <iostream>
using namespace std;

#pragma pack(1)

// A base class with virtual function foo()
class CBase
{
public:
    virtual void foo() noexcept {
        cout << "CBase::Foo() called" << endl;
    }
protected:
    int mData;
};

// A derived class with its own implementation
// of foo()
class CDerived : public CBase
{
public:
    void foo() noexcept  {
        cout << "CDerived::Foo() called" << endl;
    }
private:
    char cChar;
};

// Driver code
int main()
{
    // A base type pointer pointing to derived
    CBase *pBase = new CDerived;

    // Accessing vPtr
    int* pVPtr = *(int**)pBase;

    // Calling virtual method
    ((void(*)())pVPtr[0])();

    // Changing vPtr
    delete pBase;
    pBase = new CBase;
    pVPtr = *(int**)pBase;

    // Calls method for new base object
    ((void(*)())pVPtr[0])();

    return 0;
}


Output :


CDerived::Foo() called
CBase::Foo() called

2 java2s - java

Author: raflin

Created: 2019-04-05 五 17:18

Validate