Showing posts with label design pattern. Show all posts
Showing posts with label design pattern. Show all posts

Monday, May 27, 2013

Command Pattern

Command Pattern

What is Command Pattern?

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations

To understand command design pattern we should understand the associated key terms like client, command, command implementation, invoker, receiver.
  • Command is an interface with execute method. It is the core of contract.
  • A client creates an instance of a command implementation and associates it with a receiver.
  • An invoker instructs the command to perform an action.
  • A Command implementation’s instance creates a binding between the receiver and an action.
  • Receiver is the object that knows the actual steps to perform the action.

The following sequence diagram shows the relationship in a clearer way: 


Why need Command Pattern?
Allows the requester of a particular action to be decoupled from the object that performs the action

How to implement Command Pattern?
//Command
public interface Command
{
    public void execute();
}

//Concrete Command
public class LightOnCommand implementsCommand
{
  //reference to the light
  Light light;
 
  public LightOnCommand(Light light)
  {
      this.light = light;
  }
 
  public void execute()
  {
      light.switchOn();
  }
 
}

//Concrete Command
public class LightOffCommand implementsCommand
{
   //reference to the light
   Light light;
  
   public LightOffCommand(Light light)
   {
       this.light = light;
   }
  
   public void execute()
   {
       light.switchOff();
   }
  
}

//Receiver
public class Light
{
 private boolean on;

 public void switchOn()
 {
    on = true;
 }

 public void switchOff()
 {
    on = false;
 }

}

//Invoker
public class RemoteControl
{
  private Command command;

  public void setCommand(Command command)
  {
      this.command = command;
  }
 

  public void pressButton()
  {
      command.execute();
  }
 
}

//Client
public class Client
{
  public static void main(String[] args)
  {
      RemoteControl control = new RemoteControl();
     
      Light light = new Light();
     
      Command lightsOn = new LightsOnCommand(light);
      Command lightsOff = new LightsOffCommand(light);
     
      //switch on
      control.setCommand(lightsOn);
      control.pressButton();
     
      //switch off
      control.setCommand(lightsOff);
      control.pressButton();
 
  }


}

Another example


public interface Command {

       public abstract void execute();

}

public class OnCommand implements Command {

       private ConsumerElectronics ce;

       public OnCommand(ConsumerElectronics ce) {
              this.ce = ce;
       }

       public void execute() {
              ce.on();
       }
}

public class MuteAllCommand implements Command {
       List ceList;

       public MuteAllCommand(List ceList) {
              this.ceList = ceList;
       }

       @Override
       public void execute() {

              for (ConsumerElectronics ce : ceList) {
                     ce.mute();
              }

       }
}

public interface ConsumerElectronics {
       public abstract void on();

       public abstract void mute();
}

public class Television implements ConsumerElectronics {

       public void on() {
              System.out.println("Television is on!");
       }

       @Override
       public void mute() {
              System.out.println("Television is muted!");

       }
}

public class SoundSystem implements ConsumerElectronics {

       public void on() {
              System.out.println("Sound system is on!");
       }

       @Override
       public void mute() {
              System.out.println("Sound system is muted!");

       }
}

public class Button {
       Command c;

       public Button(Command c) {
              this.c = c;
       }

       public void click() {
              c.execute();
       }
}

public class UniversalRemote {
       public static ConsumerElectronics getActiveDevice() {
              // here we will have a complex electronic circuit :-)
              // that will maintain current device
              Television tv = new Television();
              return tv;
       }
}

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

              // OnCommand is instantiated based on active device supplied by Remote
              ConsumerElectronics ce = UniversalRemote.getActiveDevice();
              OnCommand onCommand = new OnCommand(ce);
              Button onButton = new Button(onCommand);
              onButton.click();

              Television tv = new Television();
              SoundSystem ss = new SoundSystem();
              List all = new ArrayList();
              all.add(tv);
              all.add(ss);
              MuteAllCommand muteAll = new MuteAllCommand(all);
              Button muteAllButton = new Button(muteAll);
              muteAllButton.click();

       }

}

Collusion

  • The applicability of the Command design pattern can be found in these cases below:
  • parameterizes objects depending on the action they must perform
  • specifies or adds in a queue and executes requests at different moments in time
  • offers support for undoable actions (the Execute method can memorize the state and allow going back to that state)
  • structures the system in high level operations that based on primitive operations
  • decouples the object that invokes the action from the object that performs the action. Due to this usage it is also known as Producer - Consumer design pattern.
References

Friday, May 24, 2013

Strategy Pattern

Strategy Pattern

Strategy Pattern là gì?
Đây là một behavioral pattern, định nghĩa một tập những thuật toán mà có thể chuyển đổi lẫn nhau để thực hiện một tác vụ cụ thể nào đó.


Biểu đồ sau đây cho ta thấy được cách client gọi Strategy pattern và cách nó hoạt động như thế nào:


Tại sao chúng ta cần Strategy Pattern?
Trong phát triển phần mềm, đôi lúc ta có gặp một số tình huống mà ở đó một số class nó chỉ khác nhau ở thuật toán để thực hiện công việc. Thay vì phải tạo ra nhiều classes gần như là giống nhau thì ta sẽ chỉ tách những phần thuật toán khác nhau ra thành những class khác. Sau đó việc chọn lựa sử dụng thuật toán nào đó sẽ được quyết định sau.

Cách thức để implement Strategy Pattern?
Lấy ví dụ một tool nén file
//Strategy Interface
public interface CompressionStrategy {
       public void compressFiles(ArrayList<File> files);
}

public class ZipCompressionStrategy implements CompressionStrategy {

       public void compressFiles(ArrayList<File> files) {
              // using ZIP approach
       }

}

public class RarCompressionStrategy implements CompressionStrategy {

       public void compressFiles(ArrayList<File> files) {
              // using RAR approach
       }

}

public class CompressionContext {
       private CompressionStrategy strategy;

       // this can be set at runtime by the application preferences
       public void setCompressionStrategy(CompressionStrategy strategy) {
              this.strategy = strategy;
       }

       // use the strategy
       public void createArchive(ArrayList<File> files) {
              strategy.compressFiles(files);
       }

}

public class Client {

       public static void main(String[] args)
   {
      CompressionContext ctx = new CompressionContext();
     //we could assume context is already set by preferences
      ctx.setCompressionStrategy(new ZipCompressionStrategy());    
     //get a list of files
    ...
     ctx.createArchive(fileList);   

   }
}


Một ví dụ nữa về Robot:
Chúng ta có nhiều loại Robot nhưng về cơ bản nó cũng chỉ là Robot. Điều khác nhau giữa những Robot này đó là nó có những hành động khác nhau tùy từng loại.

public interface IBehaviour {
       public int moveCommand();
}

public class AgressiveBehaviour implements IBehaviour {
       public int moveCommand() {
              System.out
                           .println("\tAgressive Behaviour: if find another robot attack it");
              return 1;
       }
}

public class DefensiveBehaviour implements IBehaviour {
       public int moveCommand() {
              System.out
                           .println("\tDefensive Behaviour: if find another robot run from it");
              return -1;
       }
}

public class NormalBehaviour implements IBehaviour {
       public int moveCommand() {
              System.out
                           .println("\tNormal Behaviour: if find another robot ignore it");
              return 0;
       }
}

public class Robot {
       IBehaviour behaviour;
       String name;

       public Robot(String name) {
              this.name = name;
       }

       public void setBehaviour(IBehaviour behaviour) {
              this.behaviour = behaviour;
       }

       public IBehaviour getBehaviour() {
              return behaviour;
       }

       public void move() {
              System.out.println(this.name + ": Based on current position"
                           + "the behaviour object decide the next move:");
              int command = behaviour.moveCommand();
              // ... send the command to mechanisms
              System.out.println("\tThe result returned by behaviour object "
                           + "is sent to the movement mechanisms " + " for the robot '"
                           + this.name + "'");
       }

       public String getName() {
              return name;
       }

       public void setName(String name) {
              this.name = name;
       }
}

public class Main {

       public static void main(String[] args) {

              Robot r1 = new Robot("Big Robot");
              Robot r2 = new Robot("George v.2.1");
              Robot r3 = new Robot("R2");

              r1.setBehaviour(new AgressiveBehaviour());
              r2.setBehaviour(new DefensiveBehaviour());
              r3.setBehaviour(new NormalBehaviour());

              r1.move();
              r2.move();
              r3.move();

              System.out.println("\r\nNew behaviours: "
                           + "\r\n\t'Big Robot' gets really scared"
                           + "\r\n\t, 'George v.2.1' becomes really mad because"
                           + "it's always attacked by other robots"
                           + "\r\n\t and R2 keeps its calm\r\n");

              r1.setBehaviour(new DefensiveBehaviour());
              r2.setBehaviour(new AgressiveBehaviour());

              r1.move();
              r2.move();
              r3.move();
       }

}

Tổng kết
Chúng ta sẽ áp dụng design pattern này khi có nhu cầu thay đổi thuật toán lúc run-time
Strategy pattern cung cấp cho ta một cách để tạo một họ những thuật toán như những Object và sau đó có thể thay đổi lẫn nhau giữa chúng lúc run-time.