1. 程式人生 > 實用技巧 >java設計模式總結(三) ---- 十一種行為型模式

java設計模式總結(三) ---- 十一種行為型模式

1 模板方法模式

理解:把執行過程的方法按照一定的順序進行放在同一個方法中,對這些過程進行統一管理

再用一個案例來說明一下:

package com.atguigu.template;

//抽象類,表示豆漿
public abstract class SoyaMilk {

    //模板方法, make , 模板方法可以做成final , 不讓子類去覆蓋.
    final void make() {
        
        select(); 
        addCondiments();
        soak();
        beat();
        
    }
    
    
//選材料 void select() { System.out.println("第一步:選擇好的新鮮黃豆 "); } //新增不同的配料, 抽象方法, 子類具體實現 abstract void addCondiments(); //浸泡 void soak() { System.out.println("第三步, 黃豆和配料開始浸泡, 需要3小時 "); } void beat() { System.out.println("第四步:黃豆和配料放到豆漿機去打碎 "); } }

配料類:

package com.atguigu.template;

public class PeanutSoyaMilk extends SoyaMilk {

    @Override
    void addCondiments() {
        // TODO Auto-generated method stub
        System.out.println(" 加入上好的花生 ");
    }

}

模板方法在Spring中的使用:

2命令模式

我們在軟體設計時,對於請求者來說我們只需要知道我們的請求(命令者)和響應(接受者)即可,其他細節我們不需要了解其細節

例項:實現對於家電控制的模擬

對於命令介面的實現:

package com.atguigu.command;


import java.util.Arrays;

//建立命令介面
public interface Command {
    //執行動作(操作)
    public void execute();
    //撤銷動作(操作)
    public void undo();
}

實現具體的傢俱:

package com.atguigu.command;

public class LightReceiver {

    public void on() {
        System.out.println(" 電燈打開了.. ");
    }
    
    public void off() {
        System.out.println(" 電燈關閉了.. ");
    }
}

空命令的初始化:

package com.atguigu.command;

/**
 * 沒有任何命令,即空執行: 用於初始化每個按鈕, 當呼叫空命令時,物件什麼都不做
 * 其實,這樣是一種設計模式, 可以省掉對空判斷
 * @author Administrator
 *
 */
public class NoCommand implements Command {

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        
    }

}

子類對於命令的具體實現(還有一個關燈方法類似):

package com.atguigu.command;

public class LightOnCommand implements Command {

    //聚合LightReceiver
    
    LightReceiver light;
    
    //構造器
    public LightOnCommand(LightReceiver light) {
        super();
        this.light = light;
    }
    
    @Override
    public void execute() {
        // TODO Auto-generated method stub
        //呼叫接收者的方法
        light.on();
    }

    

    @Override
    public void undo() {
        // TODO Auto-generated method stub
        //呼叫接收者的方法
        light.off();
    }

}

命令模式 在Spring--JDBCTemplate中的運用

個人感覺:這裡和建造者模式有一點相似。

3訪問者模式

目的:將資料結構和資料的操作進行分離。

我們用一個使用者對於評價歌手的案例來看:

package com.atguigu.visitor;

public abstract class Action {
    
    //得到男性 的測評
    public abstract void getManResult(Man man);
    
    //得到女的 測評
    public abstract void getWomanResult(Woman woman);
}
package com.atguigu.visitor;

public abstract class Person {
    
    //提供一個方法,讓訪問者可以訪問
    public abstract void accept(Action action);
}
package com.atguigu.visitor;

import java.util.LinkedList;
import java.util.List;

//資料結構,管理很多人(Man , Woman)
public class ObjectStructure {

    //維護了一個集合
    private List<Person> persons = new LinkedList<>();
    
    //增加到list
    public void attach(Person p) {
        persons.add(p);
    }
    //移除
    public void detach(Person p) {
        persons.remove(p);
    }
    
    //顯示測評情況
    public void display(Action action) {
        for(Person p: persons) {
            p.accept(action);
        }
    }
}

4迭代器模式

類比於集合中的迭代器,迭代器模式就是對於集合或者陣列中的元素進行遍歷。

讓類去繼承Iterator

迭代器模式在JDK中ArrayList中的使用

5觀察者模式

當物件間存在一對多關係時,則使用觀察者模式(Observer Pattern)。比如,當一個物件被修改時,則會自動通知依賴它的物件

當一個類改變時,其他類都會得知他的改變,我們來看一個案例,天氣

觀察者就是在Weather天氣類改變的時候,去遍歷所有類並讓他們發生變化

package com.atguigu.observer.improve;

import java.util.ArrayList;

/**
 * 類是核心
 * 1. 包含最新的天氣情況資訊 
 * 2. 含有 觀察者集合,使用ArrayList管理
 * 3. 當資料有更新時,就主動的呼叫   ArrayList, 通知所有的(接入方)就看到最新的資訊
 * @author Administrator
 *
 */
public class WeatherData implements Subject {
    private float temperatrue;
    private float pressure;
    private float humidity;
    //觀察者集合
    private ArrayList<Observer> observers;
    
    //加入新的第三方

    public WeatherData() {
        observers = new ArrayList<Observer>();
    }

    public float getTemperature() {
        return temperatrue;
    }

    public float getPressure() {
        return pressure;
    }

    public float getHumidity() {
        return humidity;
    }

    public void dataChange() {
        //呼叫 接入方的 update
        
        notifyObservers();
    }

    //當資料有更新時,就呼叫 setData
    public void setData(float temperature, float pressure, float humidity) {
        this.temperatrue = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        //呼叫dataChange, 將最新的資訊 推送給 接入方 currentConditions
        dataChange();
    }

    //註冊一個觀察者
    @Override
    public void registerObserver(Observer o) {
        // TODO Auto-generated method stub
        observers.add(o);
    }

    //移除一個觀察者
    @Override
    public void removeObserver(Observer o) {
        // TODO Auto-generated method stub
        if(observers.contains(o)) {
            observers.remove(o);
        }
    }

    //遍歷所有的觀察者,並通知
    @Override
    public void notifyObservers() {
        // TODO Auto-generated method stub
        for(int i = 0; i < observers.size(); i++) {
            observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
        }
    }
}

具體使用類:

package com.atguigu.observer.improve;

public class BaiduSite implements Observer {

    // 溫度,氣壓,溼度
    private float temperature;
    private float pressure;
    private float humidity;

    // 更新 天氣情況,是由 WeatherData 來呼叫,我使用推送模式
    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    // 顯示
    public void display() {
        System.out.println("===百度網站====");
        System.out.println("***百度網站 氣溫 : " + temperature + "***");
        System.out.println("***百度網站 氣壓: " + pressure + "***");
        System.out.println("***百度網站 溼度: " + humidity + "***");
    }

}

觀察者模式在JDK中Obsreve中的使用:

6 中介者模式

用一箇中介物件來封裝一系列的物件互動,中介者使各物件不需要顯式地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。

由一對多變成了一對一

中介者模式對於家庭電器的管理:

分析一下中介者的程式碼:

將所有需要操作的物件都放入進來,根據Register方法判斷放入HashMap中的key的值是什麼,然後value放入對應的值

再GetMessage傳入進來的類名,取出對應的類執行相關操作
ps:該類一旦出現問題,整個系統都將癱瘓
package com.atguigu.mediator.smarthouse;

import java.util.HashMap;

//具體的中介者類
public class ConcreteMediator extends Mediator {
    //集合,放入所有的同事物件
    private HashMap<String, Colleague> colleagueMap;
    private HashMap<String, String> interMap;

    public ConcreteMediator() {
        colleagueMap = new HashMap<String, Colleague>();
        interMap = new HashMap<String, String>();
    }

    @Override
    public void Register(String colleagueName, Colleague colleague) {
        // TODO Auto-generated method stub
        colleagueMap.put(colleagueName, colleague);

        // TODO Auto-generated method stub

        if (colleague instanceof Alarm) {
            interMap.put("Alarm", colleagueName);
        } else if (colleague instanceof CoffeeMachine) {
            interMap.put("CoffeeMachine", colleagueName);
        } else if (colleague instanceof TV) {
            interMap.put("TV", colleagueName);
        } else if (colleague instanceof Curtains) {
            interMap.put("Curtains", colleagueName);
        }

    }

    //具體中介者的核心方法
    //1. 根據得到訊息,完成對應任務
    //2. 中介者在這個方法,協調各個具體的同事物件,完成任務
    @Override
    public void GetMessage(int stateChange, String colleagueName) {
        // TODO Auto-generated method stub

        //處理鬧鐘發出的訊息
        if (colleagueMap.get(colleagueName) instanceof Alarm) {
            if (stateChange == 0) {
                ((CoffeeMachine) (colleagueMap.get(interMap
                        .get("CoffeeMachine")))).StartCoffee();
                ((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();
            } else if (stateChange == 1) {
                ((TV) (colleagueMap.get(interMap.get("TV")))).StopTv();
            }

        } else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {
            ((Curtains) (colleagueMap.get(interMap.get("Curtains"))))
                    .UpCurtains();

        } else if (colleagueMap.get(colleagueName) instanceof TV) {//如果TV發現訊息

        } else if (colleagueMap.get(colleagueName) instanceof Curtains) {
            //如果是以窗簾發出的訊息,這裡處理...
        }

    }

    @Override
    public void SendMessage() {
        // TODO Auto-generated method stub

    }

}

7備忘錄模式

記錄狀態情況,舉一個遊戲例子

這是一個遊戲角色的基本狀態:

package com.atguigu.memento.game;

public class Memento {

    //攻擊力
    private int vit;
    //防禦力
    private int def;
    public Memento(int vit, int def) {
        super();
        this.vit = vit;
        this.def = def;
    }
    public int getVit() {
        return vit;
    }
    public void setVit(int vit) {
        this.vit = vit;
    }
    public int getDef() {
        return def;
    }
    public void setDef(int def) {
        this.def = def;
    }
    
    
    
    
}

這是一個遊戲角色備忘錄:

package com.atguigu.memento.game;

public class Memento {

    //攻擊力
    private int vit;
    //防禦力
    private int def;
    public Memento(int vit, int def) {
        super();
        this.vit = vit;
        this.def = def;
    }
    public int getVit() {
        return vit;
    }
    public void setVit(int vit) {
        this.vit = vit;
    }
    public int getDef() {
        return def;
    }
    public void setDef(int def) {
        this.def = def;
    }
    
    
    
    
}

守護者,儲存狀態:

package com.atguigu.memento.game;

import java.util.ArrayList;
import java.util.HashMap;

//守護者物件, 儲存遊戲角色的狀態
public class Caretaker {

//如果只儲存一次狀態
private Memento memento;
//對GameRole 儲存多次狀態
//private ArrayList<Memento> mementos;
//對多個遊戲角色儲存多個狀態
//private HashMap<String, ArrayList<Memento>> rolesMementos;

public Memento getMemento() {
return memento;
}

public void setMemento(Memento memento) {
this.memento = memento;
}


}

這就是備忘錄模式

8直譯器模式

直譯器模式是對於一長串的字串進行的拆解.

package com.atguigu.interpreter;

import java.util.HashMap;

/**
 * 加法直譯器
 * @author Administrator
 *
 */
public class AddExpression extends SymbolExpression  {

    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    //處理相加
    //var 仍然是 {a=10,b=20}..
    //一會我們debug 原始碼,就ok
    public int interpreter(HashMap<String, Integer> var) {
        //super.left.interpreter(var) : 返回 left 表示式對應的值 a = 10
        //super.right.interpreter(var): 返回right 表示式對應值 b = 20
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}
package com.atguigu.interpreter;

import java.util.HashMap;
import java.util.Stack;

public class Calculator {

    // 定義表示式
    private Expression expression;

    // 建構函式傳參,並解析
    public Calculator(String expStr) { // expStr = a+b
        // 安排運算先後順序
        Stack<Expression> stack = new Stack<>();
        // 表示式拆分成字元陣列 
        char[] charArray = expStr.toCharArray();// [a, +, b]

        Expression left = null;
        Expression right = null;
        //遍歷我們的字元陣列, 即遍歷  [a, +, b]
        //針對不同的情況,做處理
        for (int i = 0; i < charArray.length; i++) {
            switch (charArray[i]) {
            case '+': //
                left = stack.pop();// 從stack取出left => "a"
                right = new VarExpression(String.valueOf(charArray[++i]));// 取出右表示式 "b"
                stack.push(new AddExpression(left, right));// 然後根據得到left 和 right 構建 AddExpresson加入stack
                break;
            case '-': // 
                left = stack.pop();
                right = new VarExpression(String.valueOf(charArray[++i]));
                stack.push(new SubExpression(left, right));
                break;
            default: 
                //如果是一個 Var 就建立要給 VarExpression 物件,並push到 stack
                stack.push(new VarExpression(String.valueOf(charArray[i])));
                break;
            }
        }
        //當遍歷完整個 charArray 陣列後,stack 就得到最後Expression
        this.expression = stack.pop();
    }

    public int run(HashMap<String, Integer> var) {
        //最後將表示式a+b和 var = {a=10,b=20}
        //然後傳遞給expression的interpreter進行解釋執行
        return this.expression.interpreter(var);
    }
}
package com.atguigu.interpreter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;

public class ClientTest {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String expStr = getExpStr(); // a+b
        HashMap<String, Integer> var = getValue(expStr);// var {a=10, b=20}
        Calculator calculator = new Calculator(expStr);
        System.out.println("運算結果:" + expStr + "=" + calculator.run(var));
    }

    // 獲得表示式
    public static String getExpStr() throws IOException {
        System.out.print("請輸入表示式:");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }

    // 獲得值對映
    public static HashMap<String, Integer> getValue(String expStr) throws IOException {
        HashMap<String, Integer> map = new HashMap<>();

        for (char ch : expStr.toCharArray()) {
            if (ch != '+' && ch != '-') {
                if (!map.containsKey(String.valueOf(ch))) {
                    System.out.print("請輸入" + String.valueOf(ch) + "的值:");
                    String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                    map.put(String.valueOf(ch), Integer.valueOf(in));
                }
            }
        }

        return map;
    }
}
package com.atguigu.interpreter;

import java.util.HashMap;

/**
 * 抽象類表示式,通過HashMap 鍵值對, 可以獲取到變數的值
 * 
 * @author Administrator
 *
 */
public abstract class Expression {
    // a + b - c
    // 解釋公式和數值, key 就是公式(表示式) 引數[a,b,c], value就是就是具體值
    // HashMap {a=10, b=20}
    public abstract int interpreter(HashMap<String, Integer> var);
}
package com.atguigu.interpreter;

import java.util.HashMap;

public class SubExpression extends SymbolExpression {

    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    //求出left 和 right 表示式相減後的結果
    public int interpreter(HashMap<String, Integer> var) {
        return super.left.interpreter(var) - super.right.interpreter(var);
    }
}
package com.atguigu.interpreter;

import java.util.HashMap;

/**
 * 抽象運算子號解析器 這裡,每個運算子號,都只和自己左右兩個數字有關係,
 * 但左右兩個數字有可能也是一個解析的結果,無論何種型別,都是Expression類的實現類
 * 
 * @author Administrator
 *
 */
public class SymbolExpression extends Expression {

    protected Expression left;
    protected Expression right;

    public SymbolExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    //因為 SymbolExpression 是讓其子類來實現,因此 interpreter 是一個預設實現
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        // TODO Auto-generated method stub
        return 0;
    }
}
package com.atguigu.interpreter;

import java.util.HashMap;


/**
 * 變數的直譯器
 * @author Administrator
 *
 */
public class VarExpression extends Expression {

    private String key; // key=a,key=b,key=c

    public VarExpression(String key) {
        this.key = key;
    }

    // var 就是{a=10, b=20}
    // interpreter 根據 變數名稱,返回對應值
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return var.get(this.key);
    }
}

直譯器模式在SpelExpressionParser中的使用

9狀態模式

每一個黃色的框框就代表一種狀態

用不同的狀態來表示相應的情況

宣告一個狀態介面:

package com.atguigu.state;

/**
 * 狀態抽象類
 * @author Administrator
 *
 */
public abstract class State {

    
    // 扣除積分 - 50
    public abstract void deductMoney();

    // 是否抽中獎品
    public abstract boolean raffle();

    // 發放獎品
    public abstract  void dispensePrize();

}

四種類型繼承該狀態:

package com.atguigu.state;

/**
 * 不能抽獎狀態
 * @author Administrator
 *
 */
public class NoRaffleState extends State {

     // 初始化時傳入活動引用,扣除積分後改變其狀態
    RaffleActivity activity;

    public NoRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }

    // 當前狀態可以扣積分 , 扣除後,將狀態設定成可以抽獎狀態
    @Override
    public void deductMoney() {
        System.out.println("扣除50積分成功,您可以抽獎了");
        activity.setState(activity.getCanRaffleState());
    }

    // 當前狀態不能抽獎
    @Override
    public boolean raffle() {
        System.out.println("扣了積分才能抽獎喔!");
        return false;
    }

    // 當前狀態不能發獎品
    @Override
    public void dispensePrize() {
        System.out.println("不能發放獎品");
    }
}
package com.atguigu.state;

/**
 * 發放獎品的狀態
 * @author Administrator
 *
 */
public class DispenseState extends State {

     // 初始化時傳入活動引用,發放獎品後改變其狀態
    RaffleActivity activity;

    public DispenseState(RaffleActivity activity) {
        this.activity = activity;
    }
    
    //

    @Override
    public void deductMoney() {
        System.out.println("不能扣除積分");
    }

    @Override
    public boolean raffle() {
        System.out.println("不能抽獎");
        return false;
    }

    //發放獎品
    @Override
    public void dispensePrize() {
        if(activity.getCount() > 0){
            System.out.println("恭喜中獎了");
            // 改變狀態為不能抽獎
            activity.setState(activity.getNoRafflleState());
        }else{
            System.out.println("很遺憾,獎品傳送完了");
            // 改變狀態為獎品傳送完畢, 後面我們就不可以抽獎
            activity.setState(activity.getDispensOutState());
            //System.out.println("抽獎活動結束");
            //System.exit(0);
        }

    }
}
package com.atguigu.state;

/**
 * 獎品發放完畢狀態
 * 說明,當我們activity 改變成 DispenseOutState, 抽獎活動結束
 * @author Administrator
 *
 */
public class DispenseOutState extends State {

    // 初始化時傳入活動引用
    RaffleActivity activity;

    public DispenseOutState(RaffleActivity activity) {
        this.activity = activity;
    }
    @Override
    public void deductMoney() {
        System.out.println("獎品傳送完了,請下次再參加");
    }

    @Override
    public boolean raffle() {
        System.out.println("獎品傳送完了,請下次再參加");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("獎品傳送完了,請下次再參加");
    }
}
package com.atguigu.state;

import java.util.Random;

/**
 * 可以抽獎的狀態
 * @author Administrator
 *
 */
public class CanRaffleState extends State {

    RaffleActivity activity;

    public CanRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }

    //已經扣除了積分,不能再扣
    @Override
    public void deductMoney() {
        System.out.println("已經扣取過了積分");
    }

    //可以抽獎, 抽完獎後,根據實際情況,改成新的狀態
    @Override
    public boolean raffle() {
        System.out.println("正在抽獎,請稍等!");
        Random r = new Random();
        int num = r.nextInt(10);
        // 10%中獎機會
        if(num == 0){
            // 改變活動狀態為發放獎品 context
            activity.setState(activity.getDispenseState());
            return true;
        }else{
            System.out.println("很遺憾沒有抽中獎品!");
            // 改變狀態為不能抽獎
            activity.setState(activity.getNoRafflleState());
            return false;
        }
    }

    // 不能發放獎品
    @Override
    public void dispensePrize() {
        System.out.println("沒中獎,不能發放獎品");
    }
}

定義一個活動類:

package com.atguigu.state;

/**
 * 抽獎活動 //
 * 
 * @author Administrator
 *
 */
public class RaffleActivity {

    // state 表示活動當前的狀態,是變化
    State state = null;
    // 獎品數量
    int count = 0;
    
    // 四個屬性,表示四種狀態
    State noRafflleState = new NoRaffleState(this);
    State canRaffleState = new CanRaffleState(this);
    
    State dispenseState =   new DispenseState(this);
    State dispensOutState = new DispenseOutState(this);

    //構造器
    //1. 初始化當前的狀態為 noRafflleState(即不能抽獎的狀態)
    //2. 初始化獎品的數量 
    public RaffleActivity( int count) {
        this.state = getNoRafflleState();
        this.count = count;
    }

    //扣分, 呼叫當前狀態的 deductMoney
    public void debuctMoney(){
        state.deductMoney();
    }

    //抽獎 
    public void raffle(){
        // 如果當前的狀態是抽獎成功
        if(state.raffle()){
            //領取獎品
            state.dispensePrize();
        }

    }

    public State getState() {
        return state;
    }

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

    //這裡請大家注意,每領取一次獎品,count--
    public int getCount() {
        int curCount = count; 
        count--;
        return curCount;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public State getNoRafflleState() {
        return noRafflleState;
    }

    public void setNoRafflleState(State noRafflleState) {
        this.noRafflleState = noRafflleState;
    }

    public State getCanRaffleState() {
        return canRaffleState;
    }

    public void setCanRaffleState(State canRaffleState) {
        this.canRaffleState = canRaffleState;
    }

    public State getDispenseState() {
        return dispenseState;
    }

    public void setDispenseState(State dispenseState) {
        this.dispenseState = dispenseState;
    }

    public State getDispensOutState() {
        return dispensOutState;
    }

    public void setDispensOutState(State dispensOutState) {
        this.dispensOutState = dispensOutState;
    }
}

然後進行測試:

package com.atguigu.state;

/**
 * 狀態模式測試類
 * @author Administrator
 *
 */
public class ClientTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // 建立活動物件,獎品有1個獎品
        RaffleActivity activity = new RaffleActivity(1);

        // 我們連續抽300次獎
        for (int i = 0; i < 30; i++) {
            System.out.println("--------第" + (i + 1) + "次抽獎----------");
            // 參加抽獎,第一步點選扣除積分
            activity.debuctMoney();

            // 第二步抽獎
            activity.raffle();
        }
    }

}

優點:1、封裝了轉換規則。 2、列舉可能的狀態,在列舉狀態之前需要確定狀態種類。 3、將所有與某個狀態有關的行為放到一個類中,並且可以方便地增加新的狀態,只需要改變物件狀態即可改變物件的行為。 4、允許狀態轉換邏輯與狀態物件合成一體,而不是某一個巨大的條件語句塊。 5、可以讓多個環境物件共享一個狀態物件,從而減少系統中物件的個數。

缺點:1、狀態模式的使用必然會增加系統類和物件的個數。 2、狀態模式的結構與實現都較為複雜,如果使用不當將導致程式結構和程式碼的混亂。 3、狀態模式對"開閉原則"的支援並不太好,對於可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的原始碼,否則無法切換到新增狀態,而且修改某個狀態類的行為也需修改對應類的原始碼。

使用場景:1、行為隨狀態改變而改變的場景。 2、條件、分支語句的代替者。

注意事項:在行為受狀態約束的時候使用狀態模式,而且狀態不超過 5 個。

10策略模式:使用介面分離把a,b,c三個方法,分成兩個介面分別有ab和bc

11職責鏈模式

完成這個專案,我們儘量少的使用esleif這樣才能增加程式碼的擴招性

於是我們就可以使用職責鏈模式:

首先擺出責任鏈:

package com.atguigu.responsibilitychain;

public abstract class Approver {

    Approver approver;  //下一個處理者
    String name; // 名字
    
    public Approver(String name) {
        // TODO Auto-generated constructor stub
        this.name = name;
    }

    //下一個處理者
    public void setApprover(Approver approver) {
        this.approver = approver;
    }
    
    //處理審批請求的方法,得到一個請求, 處理是子類完成,因此該方法做成抽象
    public abstract void processRequest(PurchaseRequest purchaseRequest);
    
}
package com.atguigu.responsibilitychain;

public class CollegeApprover extends Approver {

    public CollegeApprover(String name) {
        // TODO Auto-generated constructor stub
        super(name);
    }
    
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // TODO Auto-generated method stub
        if(purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <= 10000) {
            System.out.println(" 請求編號 id= " + purchaseRequest.getId() + " 被 " + this.name + " 處理");
        }else {
            approver.processRequest(purchaseRequest);
        }
    }
}
package com.atguigu.responsibilitychain;

public class DepartmentApprover extends Approver {

    
    public DepartmentApprover(String name) {
        // TODO Auto-generated constructor stub
        super(name);
    }
    
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // TODO Auto-generated method stub
        if(purchaseRequest.getPrice() <= 5000) {
            System.out.println(" 請求編號 id= " + purchaseRequest.getId() + " 被 " + this.name + " 處理");
        }else {
            approver.processRequest(purchaseRequest);
        }
    }

}
package com.atguigu.responsibilitychain;

public class SchoolMasterApprover extends Approver {

    public SchoolMasterApprover(String name) {
        // TODO Auto-generated constructor stub
        super(name);
    }
    
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // TODO Auto-generated method stub
        if(purchaseRequest.getPrice() > 30000) {
            System.out.println(" 請求編號 id= " + purchaseRequest.getId() + " 被 " + this.name + " 處理");
        }else {
            approver.processRequest(purchaseRequest);
        }
    }
}
package com.atguigu.responsibilitychain;

public class ViceSchoolMasterApprover extends Approver {

    public ViceSchoolMasterApprover(String name) {
        // TODO Auto-generated constructor stub
        super(name);
    }
    
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // TODO Auto-generated method stub
        if(purchaseRequest.getPrice() > 10000 && purchaseRequest.getPrice() <= 30000) {
            System.out.println(" 請求編號 id= " + purchaseRequest.getId() + " 被 " + this.name + " 處理");
        }else {
            approver.processRequest(purchaseRequest);
        }
    }
}

再給出需求物件:

package com.atguigu.responsibilitychain;


//請求類
public class PurchaseRequest {

    private int type = 0; //請求型別
    private float price = 0.0f; //請求金額
    private int id = 0;
    //構造器
    public PurchaseRequest(int type, float price, int id) {
        this.type = type;
        this.price = price;
        this.id = id;
    }
    public int getType() {
        return type;
    }
    public float getPrice() {
        return price;
    }
    public int getId() {
        return id;
    }
    
    
    
    
    
}

客戶端結果:

package com.atguigu.responsibilitychain;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //建立一個請求
        PurchaseRequest purchaseRequest = new PurchaseRequest(1, 31000, 1);
        
        //建立相關的審批人
        DepartmentApprover departmentApprover = new DepartmentApprover("張主任");
        CollegeApprover collegeApprover = new CollegeApprover("李院長");
        ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover("王副校");
        SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("佟校長");
    
    
        //需要將各個審批級別的下一個設定好 (處理人構成環形: )
        departmentApprover.setApprover(collegeApprover);
        collegeApprover.setApprover(viceSchoolMasterApprover);
        viceSchoolMasterApprover.setApprover(schoolMasterApprover);
        schoolMasterApprover.setApprover(departmentApprover);
        
        
        
        departmentApprover.processRequest(purchaseRequest);
        viceSchoolMasterApprover.processRequest(purchaseRequest);
    }

}

優點:1、降低耦合度。它將請求的傳送者和接收者解耦。 2、簡化了物件。使得物件不需要知道鏈的結構。 3、增強給物件指派職責的靈活性。通過改變鏈內的成員或者調動它們的次序,允許動態地新增或者刪除責任。 4、增加新的請求處理類很方便。

缺點:1、不能保證請求一定被接收。 2、系統性能將受到一定影響,而且在進行程式碼除錯時不太方便,可能會造成迴圈呼叫。 3、可能不容易觀察執行時的特徵,有礙於除錯。

使用場景:1、有多個物件可以處理同一個請求,具體哪個物件處理該請求由執行時刻自動確定。 2、在不明確指定接收者的情況下,向多個物件中的一個提交一個請求。 3、可動態指定一組物件處理請求。

注意事項:在 JAVA WEB 中遇到很多應用。

在SpringMVC--攔截器中的使用: