1. 程式人生 > >行為型設計模式(職責鏈模式,命令模式,中介者模式,觀察者模式,訪問者模式)

行為型設計模式(職責鏈模式,命令模式,中介者模式,觀察者模式,訪問者模式)

職責鏈模式

主要用於使多個物件都有機會處理請求,避免請求的的傳送者和接受者之間的耦合關係。在現實生活中我們多數遇到的是不純的責任鏈模式即每個物件都處理請求的一部分後再交給下家。而純的職責鏈模式則要求對於一個請求,要不處理要不就交給下家。具體理解呢。我們可以想一下“擊鼓傳花”的遊戲。或則是你幫你的同學傳一個紙條。如果傳給你你就看,否則就傳給下一個同學(嘻嘻)。比較容易理解,主要看一下類圖:


和相關程式碼實現:

public abstract class Handler {
    
    /**
     * 持有後繼的責任物件
     */
    protected Handler successor;
    
/** * 示意處理請求的方法,雖然這個示意方法是沒有傳入引數的 * 但實際是可以傳入引數的,根據具體需要來選擇是否傳遞引數 */ public abstract void handleRequest(); /** * 取值方法 */ public Handler getSuccessor() { return successor; } /** * 賦值方法,設定後繼的責任物件 */ public void setSuccessor(Handler successor) {
this.successor = successor; } }
複製程式碼

  具體處理者角色

複製程式碼
public class ConcreteHandler extends Handler {
    /**
     * 處理方法,呼叫此方法處理請求
     */
    @Override
    public void handleRequest() {
        /**
         * 判斷是否有後繼的責任物件
         * 如果有,就轉發請求給後繼的責任物件
         * 如果沒有,則處理請求
         */
        if(getSuccessor() != null
) { System.out.println("放過請求"); getSuccessor().handleRequest(); }else { System.out.println("處理請求"); } } }
複製程式碼

  客戶端類

複製程式碼
public class Client {

    public static void main(String[] args) {
        //組裝責任鏈
        Handler handler1 = new ConcreteHandler();
        Handler handler2 = new ConcreteHandler();
        handler1.setSuccessor(handler2);
        //提交請求
        handler1.handleRequest();
    }

}
命令模式。

主要用於把發出命令和執行命令的責任分開,委派給不同物件。怎麼理解呢?命令模式中請求的實現在接受者中實現但在最後客戶請求服務時。具體的實現是通過請求者呼叫具體命令角色來實現。舉個例子。錄音機(播放,倒帶,停止)三個功能

接收者角色,由錄音機類扮演

複製程式碼
public class AudioPlayer {
    
    public void play(){
        System.out.println("播放...");
    }
    
    public void rewind(){
        System.out.println("倒帶...");
    }
    
    public void stop(){
        System.out.println("停止...");
    }
}
複製程式碼

  抽象命令角色類

複製程式碼
public interface Command {
    /**
     * 執行方法
     */
    public void execute();
}
複製程式碼

  具體命令角色類

複製程式碼
public class PlayCommand implements Command {

    private AudioPlayer myAudio;
    
    public PlayCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    /**
     * 執行方法
     */
    @Override
    public void execute() {
        myAudio.play();
    }

}
複製程式碼 複製程式碼
public class RewindCommand implements Command {

    private AudioPlayer myAudio;
    
    public RewindCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    @Override
    public void execute() {
        myAudio.rewind();
    }

}
複製程式碼 複製程式碼
public class StopCommand implements Command {
    private AudioPlayer myAudio;
    
    public StopCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    @Override
    public void execute() {
        myAudio.stop();
    }

}
複製程式碼

  請求者角色,由鍵盤類扮演

複製程式碼
public class Keypad {
    private Command playCommand;
    private Command rewindCommand;
    private Command stopCommand;
    
    public void setPlayCommand(Command playCommand) {
        this.playCommand = playCommand;
    }
    public void setRewindCommand(Command rewindCommand) {
        this.rewindCommand = rewindCommand;
    }
    public void setStopCommand(Command stopCommand) {
        this.stopCommand = stopCommand;
    }
    /**
     * 執行播放方法
     */
    public void play(){
        playCommand.execute();
    }
    /**
     * 執行倒帶方法
     */
    public void rewind(){
        rewindCommand.execute();
    }
    /**
     * 執行播放方法
     */
    public void stop(){
        stopCommand.execute();
    }
}
複製程式碼

  客戶端角色,由茱麗小女孩扮演

複製程式碼
public class Julia {
    public static void main(String[]args){
        //建立接收者物件
        AudioPlayer audioPlayer = new AudioPlayer();
        //建立命令物件
        Command playCommand = new PlayCommand(audioPlayer);
        Command rewindCommand = new RewindCommand(audioPlayer);
        Command stopCommand = new StopCommand(audioPlayer);
        //建立請求者物件
        Keypad keypad = new Keypad();
        keypad.setPlayCommand(playCommand);
        keypad.setRewindCommand(rewindCommand);
        keypad.setStopCommand(stopCommand);
        //測試
        keypad.play();
        keypad.rewind();
        keypad.stop();
        keypad.play();
        keypad.stop();
    }
}
在例子之後我們再看類圖是不就感覺簡單一些


中介者模式

使用場景:集中負責維護物件模型的關係完整性 以及需要 封裝物件間互動方式的時候.
   其實MVC中的controller就是一種Mediator,是UI層 和後端應用sevice層間的中介者。中介者將互動的複雜性變為中介者的複雜性

 在此寫了7個java類來描述說明Mediator設計模式的實現方式;

  1、 Colleague.java   互動物件的抽象類
  2、 Colleague1.java  互動物件1
  3、 Colleague2.java  互動物件2
  4、 Colleague3.java  互動物件3
  5、 Mediator.java    中介者抽象類
  6、 ConcreteMediator.java 具體的中介者
  7、 MediatorTest.java     帶有main方法的測試類

===============   1、 Colleague.java
互動物件的抽象類,定義了中介者的注入方法 、互動的行為方法
package mediator;

public abstract class Colleague {
  //中介者
  private Mediator mediator;
  public Mediator getMediator() {
    return mediator;
  }
  public Colleague(Mediator m) {
    mediator = m;
  }
 
  //訊息
  private String message;
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }

  //傳送訊息
  public abstract void sendMsg();

  //收到訊息
  public abstract void getMsg(String msg);

  //傳送訊息
  public void sendMsg(String msg) {
    this.message = msg;
    mediator.action(this);
  }
}
===============   1 end

===============   2、 Colleague1.java
package mediator;

public class Colleague1 extends Colleague {
  public Colleague1(Mediator m) {
    super(m);
  }

  public void getMsg(String msg) {
    System.out.println("Colleague1 has got  the message  -'" + msg + "'");
  }

  public void sendMsg() {
    System.out.println("Colleague1 has send the message '" + getMessage() + "'");
  }
}
===============   2 end

===============   3、 Colleague2.java
package mediator;

public class Colleague2 extends Colleague {
  public Colleague2(Mediator m) {
    super(m);
  }

  public void getMsg(String msg) {
    System.out.println("Colleague2 has got  the message  -'" + msg + "'");
  }

  public void sendMsg() {
    System.out.println("Colleague2 has send the message '" + getMessage() + "'");
  }
}
===============   3 end

===============   4、 Colleague3.java
package mediator;

public class Colleague3 extends Colleague {
  public Colleague3(Mediator m) {
    super(m);
  }

  public void getMsg(String msg) {
    System.out.println("Colleague3 has got  the message  -'" + msg + "'");
  }

  public void sendMsg() {
    System.out.println("Colleague3 has send the message '" + getMessage() + "'");
  }
}
===============   4 end

===============   5、 Mediator.java
package mediator;

abstract class Mediator {
  //Mediator針對Colleague的一個互動行為
  public abstract void action(Colleague sender);
  //加入Colleague物件
  public abstract void addCollegue(Colleague colleague);
}
===============   5 end

===============   6、 ConcreteMediator.java
  具體的中介者,負責管理Colleague物件間的關係、以及Colleague物件間的互動
package mediator;

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

public class ConcreteMediator extends Mediator {

  private List<Colleague> colleagues = new ArrayList<Colleague>(0);
 
  public void addCollegue(Colleague colleague) {
    colleagues.add(colleague);
  }

  public void action(Colleague actor) {
    String msg = actor.getMessage();
    //send msg
    for (Colleague colleague : colleagues) {
      if(colleague.equals(actor)){
        colleague.sendMsg();
        break;
      }
    }
   
    //get msg
    for (Colleague colleague : colleagues) {
      if(colleague.equals(actor))
        continue;
       
      colleague.getMsg(msg);
    }
  }
}
===============   6 end

===============   7、 MediatorTest.java
package mediator;

public class MediatorTest {

  public static void main(String[] args) {
   //生成中介者 並注入到各個Colleague物件中
    Mediator mediator = new ConcreteMediator();
    Colleague colleague1 = new Colleague1(mediator);
    Colleague colleague2 = new Colleague2(mediator);
    Colleague colleague3 = new Colleague3(mediator);
 
 //註冊物件到中介
    mediator.addCollegue(colleague1);
    mediator.addCollegue(colleague2);
    mediator.addCollegue(colleague3);
   
 //Colleague1 觸發行為
    colleague1.sendMsg("Hi,it's time to lunch. Let's go!");
    System.out.println();
    //Colleague2 觸發行為
    colleague2.sendMsg("Is anybody here!");
    System.out.println();
    //Colleague3 觸發行為
    colleague3.sendMsg("Wait!I will lunch off right away.");
    System.out.println();
   
  }
}

觀察者模式

觀察者模式又稱為釋出訂閱模式,模型檢視模式,源-監聽器模式。它定義一種一對多的依賴關係,讓多個觀察者同時監聽一個主題物件。這個主題物件發生改變時,所有觀察者做出相應變化。例如我們買衣服。我們去買衣服結果沒貨。我們會把自己的聯絡方式留下來(註冊),等有貨時商家通知你。其實這就是一個觀察者模式。我們以及其他買衣服者是觀察者,商家是被觀察者。商家狀態改變(有衣服),通知觀察者,觀察者也做出相應變化(去買衣服)。一個簡單的Java例子:

//抽象觀察者角色
public interface Watcher
{
    public void update(String str);

}
複製程式碼

  然後定義抽象的主題角色,即抽象的被觀察者,在其中宣告方法(新增、移除觀察者,通知觀察者):

複製程式碼
//抽象主題角色,watched:被觀察
public interface Watched
{
    public void addWatcher(Watcher watcher);

    public void removeWatcher(Watcher watcher);

    public void notifyWatchers(String str);

}
複製程式碼

  然後定義具體的觀察者:

複製程式碼
public class ConcreteWatcher implements Watcher
{

    @Override
    public void update(String str)
    {
        System.out.println(str);
    }

}
複製程式碼

  之後是具體的主題角色:

複製程式碼
import java.util.ArrayList;
import java.util.List;

public class ConcreteWatched implements Watched
{
    // 存放觀察者
    private List<Watcher> list = new ArrayList<Watcher>();

    @Override
    public void addWatcher(Watcher watcher)
    {
        list.add(watcher);
    }

    @Override
    public void removeWatcher(Watcher watcher)
    {
        list.remove(watcher);
    }

    @Override
    public void notifyWatchers(String str)
    {
        // 自動呼叫實際上是主題進行呼叫的
        for (Watcher watcher : list)
        {
            watcher.update(str);
        }
    }

}
複製程式碼

  編寫測試類:

複製程式碼
public class Test
{
    public static void main(String[] args)
    {
        Watched girl = new ConcreteWatched();
        
        Watcher watcher1 = new ConcreteWatcher();
        Watcher watcher2 = new ConcreteWatcher();
        Watcher watcher3 = new ConcreteWatcher();
        
        girl.addWatcher(watcher1);
        girl.addWatcher(watcher2);
        girl.addWatcher(watcher3);
        
        girl.notifyWatchers("開心");
    }

}
訪問者模式

訪問者模式適用於資料結構相對穩定的系統,它將演算法與物件結構分離開,是操作能相對自由的演化。看一下類圖

Java 設計模式 之 訪問者模式(Visitor) - 低調的華麗 - 輝色空間

public abstract class Customer {

         private String customerId;
         private String name;
 
         public String getCustomerId() {
                   return customerId;
         }
         public void setCustomerId(String customerId) {
                  this.customerId = customerId;
         }
         public String getName() {
                  return name;
         }
         public void setName(String name) {
                 this.name = name;
         }
 
         /**
          * 接受訪問者的訪問
          * @param visitor
          */
         public abstract void accept(Visitor visitor);

/**
 * 企業客戶
 */
public class EnterpriseCustomer extends Customer {

          private String linkman;
          private String linkTelephone;
          private String registerAddress;
 
          public String getLinkman() {
                    return linkman;
          }

          public void setLinkman(String linkman) {
                   this.linkman = linkman;
          }

          public String getLinkTelephone() {
                  return linkTelephone;
          }

          public void setLinkTelephone(String linkTelephone) {
                  this.linkTelephone = linkTelephone;
          }

          public String getRegisterAddress() {
                  return registerAddress;
          }

          public void setRegisterAddress(String registerAddress) {
                    this.registerAddress = registerAddress;
          }

          @Override
          public void accept(Visitor visitor) {
                   //回撥訪問者物件的方法
                   visitor.visitEnterpriseCustomer(this);
          }

}

/**
 * 個人客戶
 */
public class PersonalCustomer extends Customer {

          private String telephone;
          private int age;
 
          public String getTelephone() {
                    return telephone;
          }

          public void setTelephone(String telephone) {
                   this.telephone = telephone;
          }

          public int getAge() {
                  return age;
          }

          public void setAge(int age) {
                  this.age = age;
          }

          @Override
          public void accept(Visitor visitor) {
                   //回撥訪問者物件的方法
                   visitor.visitPersonalCustomer(this);
          }

}

/**
 * 訪問者介面
 */
public interface Visitor {

          /**
           * 訪問企業客戶,相當於給企業客戶新增訪問者功能
           * @param ec 企業客戶物件
           */
          public void visitEnterpriseCustomer(EnterpriseCustomer ec);
          /**
           * 訪問個人客戶,相當於給個人客戶新增訪問者的功能
           * @param pc
           */
          public void visitPersonalCustomer(PersonalCustomer pc);
}

/**
 * 具體的訪問者,實現對客戶的偏好分析
 */
public class PredilectionAnalyzeVisitor implements Visitor {

           @Override
           public void visitEnterpriseCustomer(EnterpriseCustomer ec) {
                   // TODO 根據以往的購買歷史、潛在購買意向,以及客戶所在行業的發展趨勢、客戶的發展趨勢等的分析
                   System.out.println("現在對企業客戶" + ec.getName() + "進行產品偏好分析");
           }

           @Override
           public void visitPersonalCustomer(PersonalCustomer pc) {
                   System.out.println("現在對個人客戶" + pc.getName() + "進行產品偏好分析");
           }

}

/**
 * 具體的訪問者,實現客戶提出服務請求的功能
 */
public class ServiceRequestVisitor implements Visitor {

           @Override
            public void visitEnterpriseCustomer(EnterpriseCustomer ec) {
                       // TODO 企業客戶提出的具體服務請求
                       System.out.println(ec.getName() + "企業提出服務請求");
            }

            @Override
            public void visitPersonalCustomer(PersonalCustomer pc) {
                      // TODO 個人客戶提