設計模式三-行爲模式

策略設計模式

策略設計模式也叫算法族模式。目的是該算法改變的時候並不影響客戶的使用。實現的基本思路非常簡單,定義一個算法接口,然後各種不同的算法去實現這個接口,客戶端調用使用的是接口而不是實現,說以當改變實現的時候客戶端是不需要改變的。

/*
 * 策略模式,又叫算法簇模式,就是定義了不同的算法族,並且之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶。
 */
public interface ICalculator {
    public void calculate();
}
/**
 * 算法1
 */
public class Algorithm1 implements ICalculator{

    @Override
    public void calculate() {
    System.out.println("這是算法1");

    }

}
/*
 * 算法2
 */
public class Algorithm2 implements ICalculator {

    @Override
    public void calculate() {
        System.out.println("這是算法2");
    }

}
public class Client {
    public static void main(String[] args) {
    //當改變算法實現的時候改變這裏創建的對象即可
        ICalculator calculator = new Algorithm1();
        calculator.calculate();
    }
}

模板設計模式

意圖:定義實現一個邏輯的基本框架或者步驟,具體如何實現要由子類去完成。
原理:定義一個抽象類,抽象類中必須給出一個啓動該邏輯的具體方法。邏輯的實現步驟由抽象方法定義。然後在具體方法中調用這些抽象方法。這樣一個模板類就定義好了。要實現該模板類直接繼承該模板類就OK了。

給出一個小例子:

/**
 * 模板類
 */
public abstract class Template {
    public void Calculate() {
        //這裏不只是可以調用抽象方法,已經實現的方法或者是空方法都可調用
        method1();
        method2();
        method3();
        hookMethod();
    }

    /*
     * 邏輯實現的基本步驟交給子類去實現
     */
    public abstract void method1();

    public abstract void method2();

    public abstract void method3();
    /**
     * hook方法,可以在子類中override
     */
    public void hookMethod(){}
}
/**
 * 模板的實現類
 */
public class ConcreteTemplate extends Template {

    @Override
    public void method1() {
    System.out.println("method1");

    }

    @Override
    public void method2() {
        System.out.println("method2");

    }

    @Override
    public void method3() {
        System.out.println("method3");

    }
    @Override
    public void hookMethod(){
        System.out.println("hookmethod");
    }
}

public class Client {
    public static void main(String[] args) {
    Template template=new ConcreteTemplate();
    template.Calculate();

    }

}

輸出:
method1
method2
method3
hookmethod

觀察者模式

意圖:觀察者模式解決的問題是當一個對象發生改變的時候,要通知其他的對象發生了改變。
實現:被觀察者對象內部維護一個隊列,隊列裏邊存放着觀察者的引用。當被觀察者狀態發生改變的時候就會遍歷隊列裏邊的觀察者並通知它們狀態改變了。

import java.util.Observable;
import java.util.Observer;

/*
 * java爲方便我們使用觀察者模式,爲我們提供了觀察者的接口定義。
 */
public class Observer1 implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("收到狀態更新的通知");

    }

}
import java.util.Observable;
import java.util.Observer;


public class Observer2 implements Observer{

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("收到狀態更新的通知");

    }

}
import java.util.Observable;
/*
 * java爲方便我們使用觀察者模式,爲我們提供了被觀察者的接口定義。
 * 在這個抽象類中維護了一個集合和對這個集合進行操作的方法。有興趣的可以看一下源碼
 */
public class Subject extends Observable {
    // 更新狀態,通知觀察者
    public void Operation() {
        System.out.println("update State");
        setChanged();
        notifyObservers();
    }
}
import java.util.Observer;

public class Client {
    public static void main(String[] args) {
        //創建倆個觀察者對象
        Observer observer1 = new Observer1();
        Observer observer2 = new Observer2();
        //創建被觀察者
        Subject subject = new Subject();
        //添加觀察者到被觀察者中去
        subject.addObserver(observer1);
        subject.addObserver(observer2);
        //更新被觀察者的狀態
        subject.Operation();
    }

}

迭代器模式(Iterator)

目的:實現類似遊標遍歷集合中的內容一樣的效果。
原理:直接看代碼吧。

/**
 * 定義一個容器要實現的接口
 */
public interface Iteratorabel {
    public Iterator Iterator();
}
/*
 * 定義遊標接口
 */
public interface Iterator {
      //前移  
    public Object previous();  

    //後移  
    public Object next();  
    public boolean hasNext();  

    //取得第一個元素  
    public Object first();  
}
/*
 * 定義一個容器應該有的基本方法
 */
public abstract class Collection implements Iteratorabel {

    @Override
    public Iterator Iterator() {
        // TODO Auto-generated method stub
        return null;
    }

    /*
     * 添加一個對象
     */
    public abstract void add(Object object);

    /*
     * 獲取一個對象
     */
    public abstract void get(int i);

    /*
     * 刪除一個對象
     */
    public abstract void remove(Object object);
}
/*
 * 實現一個容器實例
 */
public class MyCollection extends Collection {
    @Override
    public Iterator Iterator() {
        return new MyIterator(this);
    }

    @Override
    public void add(Object object) {
        System.out.println("add");
    }

    @Override
    public void get(int i) {
        System.out.println("get" + i);

    }

    @Override
    public void remove(Object object) {
        System.out.println("remove");

    }

}
/*
 * 實現一個遊標
 */
public class MyIterator implements Iterator {
    Collection collection;

    public MyIterator(Collection collection) {
        this.collection = collection;
    }

    @Override
    public Object previous() {
        System.out.println("previous");
        return null;
    }

    @Override
    public Object next() {
        System.out.println("next");
        return null;
    }

    @Override
    public boolean hasNext() {
        System.out.println("has next");
        return false;
    }

    @Override
    public Object first() {
        System.out.println("first");
        return null;
    }
}
/*
 * 客戶端
 */
public class Clietn {
    public static void main(String[] args) {
        //創建一個自定義集合
        Collection collection = new MyCollection();
        //返回它的迭代器
        Iterator iterator = collection.Iterator();
        //使用迭代器
        iterator.hasNext();
    }

}

責任鏈模式

目的:有多個對象,每個對象持有對下一個對象的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。但是發出者並不清楚到底最終那個對象會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。
這裏寫圖片描述
實現:Abstracthandler類提供了get和set方法,方便MyHandle類設置和修改引用對象,MyHandle類是核心,實例化後生成一系列相互持有的對象,構成一條鏈。

/*
 * 定義處理任務需要實現的方法
 */
public interface IHandler {
    public void Operation();
}
/*
 * 定義形成責任鏈的基本框架
 */
public abstract class AbsHandler {
    //存儲責任鏈上的下一個對象
    private IHandler handler;

    public IHandler getHandler() {
        return handler;
    }

    public void setHandler(IHandler handler) {
        this.handler = handler;
    }

}
/*
 * 責任鏈模式的實現類
 */
public class MyHandler extends AbsHandler implements IHandler {

    @Override
    public void Operation() {
        System.out.println("I am " + this);
        if (getHandler() != null) {
            getHandler().Operation();
        }
    }

}
/*
 * 客戶端
 */
public class Client {
    public static void main(String[] args) {
        MyHandler h1 = new MyHandler();

        MyHandler h2 = new MyHandler();
        //設置責任鏈上的下一個處理對象
        h1.setHandler(h2);

        h1.Operation();
    }

}

命令設計模式

目的:實現命令的發送和執行者的解耦合
下面模擬一個使用遙控器控制電視打開關閉切換頻道的功能:

/*
 * 定義一條命令
 */
public interface Command {
    public void excute();
}
/*
 * 切換頻道的命令
 */
public class ChangeChanelCommand implements Command{
private TVReciver reciver;
public ChangeChanelCommand(TVReciver reciver){
    this.reciver=reciver;
}
    @Override
    public void excute() {
        reciver.changchanle();
    }

}
/*
 * 關閉電視的命令
 */
public class TurnoffCommand implements Command {
    private TVReciver reciver;

    public TurnoffCommand(TVReciver reciver) {
        this.reciver = reciver;
    }

    @Override
    public void excute() {
        reciver.turnoff();

    }

}
/*
 * 打開電視的命令
 */
public class TurnOnCommand implements Command {
    private TVReciver reciver;

    public TurnOnCommand(TVReciver reciver) {
        this.reciver = reciver;
    }

    @Override
    public void excute() {

        reciver.turnon();
    }

}
/*
 1. 命令接收着
 */
public class TVReciver {
    public void turnon() {
        System.out.println("打開電視");
    }

    public void changchanle() {
        System.out.println("切換頻道");
    }

    public void turnoff() {
        System.out.println("關閉電視");
    }
}
/*
 2. 控制者,相當於invoker
 */
public class Controller {
    private Command onCommand, offCommand, changeChannel;

    public Controller(Command on, Command off, Command channel) {
        this.onCommand = on;
        this.offCommand = off;
        this.changeChannel = channel;
    }

    public void turnOn() {
        onCommand.excute();
    }

    public void turnOff() {
        offCommand.excute();
    }

    public void changeChannel() {
        changeChannel.excute();
    }
}
/*
 3. 客戶端
 4. 命令模式的目的是實現命令的發送和執行者的解耦合。那麼使用一個Command接口不就可以隔離命令的發送和實現麼,爲什麼還要有一個接收者?
 5. 
 6. 關於這一點,是爲了使這個模式更加的靈活同時也是符合現實的生活(面向對象嘛)。首先,作爲一個命令的實際執行者,它不可能只會執行一條命
 7. 令,一般來說他會同時具備執行幾個命令的能力。其次,當有一些複雜命令可以由其他的命令組合完成的時候,這個時候就可以複用接收者的這些個
 8. 能力了,代碼更加靈活。

 */
public class Client {
    public static void main(String[] args) {
        // 命令的實際執行者
        TVReciver reciver = new TVReciver();
        // 創建命令
        Command commaTurnoffCommand = new TurnoffCommand(reciver);
        Command turnOnCommand = new TurnOnCommand(reciver);
        Command chanelCommand = new ChangeChanelCommand(reciver);
        // 命令發出者
        Controller controller = new Controller(turnOnCommand,
                commaTurnoffCommand, chanelCommand);
        // 發送命令
        controller.turnOn();
        controller.changeChannel();
        controller.turnOff();
    }
}

輸出結果:

打開電視
切換頻道
關閉電視

備忘錄模式

目的:該模式的目的就是保存一個類的狀態,在需要的時候恢復其狀態。
原理:對於要恢復的類,我們需要對其必要的屬性進行保存。然後在需要恢復其屬性的時候根據已近保存的屬性值進行賦值恢復其狀態。

這裏給出的例子,存儲方式是存儲在內存中,也可以選擇其他的存儲方式。

/*
 1. 需要保存狀態的類
 */
public class Original {
    private String value;

    public Original(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    // 創建一個備份
    public Memento CreatMemento() {
        return new Memento(value);
    }

    // 還原狀態
    public void Restorage(Memento memento) {
        this.value = memento.getValue();
    }
}
/*
 2. 備忘錄類
 */
public class Memento {
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Memento(String value) {
        this.value = value;
    }
}
/*
 3. 保存備忘錄類
 */
public class Storage {

  private Memento memento;  

  public Storage(Memento memento) {  
      this.memento = memento;  
  }  

  public Memento getMemento() {  
      return memento;  
  }  

  public void setMemento(Memento memento) {  
      this.memento = memento;  
  }
}
public class Client {
    public static void main(String[] args) {
        // 創建原始類
        Original origi = new Original("egg");

        // 創建備忘錄
        Storage storage = new Storage(origi.CreatMemento());

        // 修改原始類的狀態
        System.out.println("初始化狀態爲:" + origi.getValue());
        origi.setValue("niu");
        System.out.println("修改後的狀態爲:" + origi.getValue());

        // 回覆原始類的狀態
        origi.Restorage(storage.getMemento());
        System.out.println("恢復後的狀態爲:" + origi.getValue());
    }
}

輸出結果:
初始化狀態爲:egg
修改後的狀態爲:niu
恢復後的狀態爲:egg

狀態設計模式

狀態設計模式

目的:當狀態改變的時候,改變其行爲。很好理解!就拿QQ來說,有幾種狀態,在線、隱身、忙碌等,每個狀態對應不同的操作,而且你的好友也能看到你的狀態,所以,狀態模式就兩點:1、可以通過改變狀態來獲得不同的行爲。2、你的好友能同時看到你的變化。

/*
 * 狀態模式的核心類
 */
public class State {
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public State(String value) {
        this.value = value;
    }
     public void method1(){  
            System.out.println("execute the first opt!");  
        }  

        public void method2(){  
            System.out.println("execute the second opt!");  
        }  
}
/*
 * 狀態切換類
 */
public class Context {
    private State state;  

    public Context(State state) {  
        this.state = state;  
    }  

    public State getState() {  
        return state;  
    }  

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

    public void method() {  
        if (state.getValue().equals("state1")) {  
            state.method1();  
        } else if (state.getValue().equals("state2")) {  
            state.method2();  
        }  
    }  
}
/*
 * 測試
 */
public class Test {

    public static void main(String[] args) {
           State state = new State("");  
            Context context = new Context(state);  

            //設置第一種狀態  
            state.setValue("state1");  
            context.method();  

            //設置第二種狀態  
            state.setValue("state2");  
            context.method();
    }

}

訪問者設計模式

目的:訪問者模式適用於數據結構相對未定的系統,它把數據結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化。
例子:

/*
 * 必須實現accept方法,以便實現Visitor和Node的雙向引用。目的的達到在visitor中對調Node中訪問數據的方法。
 */
public abstract class Node {
    /**
     * 接受操作
     */
    public abstract void accept(Visitor visitor);
}
/*
 * 通過傳入的Node數據對象訪問數據,實現對數據的操作。
 */
public interface Visitor {
    /**
     * 對應於NodeA的訪問操作
     */
    public void visit(NodeA node);
    /**
     * 對應於NodeB的訪問操作
     */
    public void visit(NodeB node);
}
public class VisitorA implements Visitor {
    /**
     * 對應於NodeA的訪問操作
     */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
     * 對應於NodeB的訪問操作
     */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }
}
public class VisitorB implements Visitor {
    /**
     * 對應於NodeA的訪問操作
     */
    @Override
    public void visit(NodeA node) {
        System.out.println(node.operationA());
    }
    /**
     * 對應於NodeB的訪問操作
     */
    @Override
    public void visit(NodeB node) {
        System.out.println(node.operationB());
    }
}
public class NodeA extends Node{
    /**
     * 接受操作
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
     * NodeA特有的方法
     */
    public String operationA(){
        return "NodeA";
    }
}

public class NodeB extends Node{
    /**
     * 接受方法
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    /**
     * NodeB特有的方法
     */
    public String operationB(){
        return "NodeB";
    }
}
import java.util.ArrayList;
import java.util.List;
/*
 * 存放數據訪問Node
 */
public class ObjectStructure {

    private List<Node> nodes = new ArrayList<Node>();

    /**
     * 執行方法操作
     */
    public void action(Visitor visitor){

        for(Node node : nodes)
        {
            /*
             * 一:accept node中獲得了visitor的引用
             * 二:node 反過來調用visitor的visit(Node node)方法 。此時node將自己的this傳入。完成了Node和visitor之間的
             * 雙重引用。在visitor方法中,傳入的Node被調用,此時visitor就訪問到了Node中的數據。接下來可以進行其他操作了。
             */
            node.accept(visitor);
        }

    }
    /**
     * 添加一個新元素
     */
    public void add(Node node){
        nodes.add(node);
    }
}
/*
 * 在數據結構不變的情況下,改變上層對數據的操作可以使用訪問者設計模式。
 */
public class Client {

    public static void main(String[] args) {
          //創建一個結構對象
        ObjectStructure os = new ObjectStructure();
        //給結構增加一個節點
        os.add(new NodeA());
        //給結構增加一個節點
        os.add(new NodeB());
        //創建一個訪問者
        Visitor visitor = new VisitorA();
        os.action(visitor);
    }
}

結果:
NodeA
NodeB

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章