文章目錄
行爲型模式:關注系統中對象之間的交互,以及相互通信協作,進一步明確對象的職責
類行爲型模式:通過多態來分配父子的職責。
對象行爲型模式:通過對象關聯等方式職責分配職責。
職責鏈模式
職責鏈模式:將請求的發送者與接收者解耦,讓接收請求的對象連接成一條鏈,並且沿着這條鏈傳遞請求,直到有一個能處理它爲止。
職責鏈數據結構
抽象處理者(Handler):定義一個處理請求的接口,關聯一個抽象處理者類型的對象作爲對下家的引用,由此構成一條鏈
具體處理者(ConcreteHandler):實現抽象處理者處理用戶請求,處理請求之前需要檢查是否有權限,如果可以處理就處理,否則進行轉發。
職責鏈模式實現
## 定義抽象處理者
public abstract class Handler{
protected Handler successor;
public void setSuccessor(Handler successor){
this.successor=successor;
}
public abstract void handleRequest(String request);
}
## 定義具體處理者
public class ConcereteHandler extends Handler{
public void handleRequest(String request){
if(滿足某條件){
//處理請求
}else{
//轉發請求
this.successor.handleRequest(request);
}
}
}
職責鏈優缺點
優點:
- 客戶端無需知道哪一個對象處理它的請求
- 請求處理對象維持一個指向後繼者的引用,簡化對象的連接
- 可通過在運行時對該鏈進行動態增加or刪除改變處理一個請求的職責
- 系統增加具體處理者無需修改原有代碼,只需要客戶端重新創建鏈即可,滿足開閉原則
缺點:
a)沒有明確接收者,不能保證被處理
b)對請求鏈長的職責鏈,系統性能收到影響
職責鏈適用環境
例如:web應用中創建多個過濾器Filter鏈來對請求進行過濾
工作流系統中實現辦公的分級審批
異常處理機制,不同的catch子句構成了一條處理異常對象的職責鏈
- 有多個對象可以處理請求
- 在不明確指定接收者的情況下向多個對象中的一個提交一個請求
- 客戶端動態指定一組對象處理請求,而且還可以改變鏈中的執行順序
命令模式
它將請求發送者,請求接收者解耦,可以讓相同的發送者對應不同的接收者。
命令模式定義:將一個請求封裝成一個對象,從而通過不同的請求將客戶端參數化,實現了請求排隊,記錄請求日誌,可撤銷操作
命令模式數據結構
- 抽象命令類(Command):其中聲明瞭執行請求的execute()方法,調用接收者的相關操作
- 具體命令類(ConcereteCommand):對應具體的接收者對象,將接收者對象的動作綁定其中、
- 調用者(Invoker):請求發送者,它通過命令對象執行請求【設計時不需要指定接收者,運行時將具體命令對象注入,然後調用命令對象的excute方法,從而實現間接調用請求接收者的相關詞操作】
- 接收者(Receiver):接收者執行與請求相關操作,具體實現對請求的業務處理
命令模式的實現
## 定義抽象命令類
public abstract class Command{
public abstract void excute();
}
## 定請求發送者,也就是調用者
public class Invoker{
private Command command;
public Invoker(Command command){
this.command=command;
}
//業務方法
public void call{
command.execute();
}
}
## 定義具體命令類
public class ConcereteCommand extends Command{
private Receiver receiver; //維持一個對請求接收者的引用
//調用請求接收者的也無法方法
public void excute(){
receiver.action();
}
}
## 定義請求接收者
public clas Receiver{
public void action(){
//具體操作
}
}
實現命令隊列
請求發送者發送一個請求會有多個請求接收者產生響應。
- 可以對一組命令進行批量處理,從而設計批量處理程序。
- 如果請求接收者對請求次序沒有要求,還可以使用多線程技術來併發調用對象的excute方法,提高執行效率
## 增加一個命令隊列
public class CommandQueue{
private List<Command> commands=new ArrayList<Command>();
public addCommand(Command command){commands.add(command)}
public void excute(){
for(Object command:commands){
command.excute();
}
}
}
## 重寫調用者
public class Invoker{
private CommandQueue commandQueue; //維護commandQueue的引用
public Invoker(CommandQueue commandQueue){
this.commandQueue=commandQueue;
}
public void call(){
commandQueue.excute();
}
}
記錄請求日誌-實現撤銷功能-宏命令
命令模式優缺點
優點
- 系統通過引入抽象命令,將請求者和接收者實現完全解耦
- 系統新增新得命令不會修改原有代碼
- 比較容易設計一個命令隊列,宏命令
- 爲請求的撤銷和恢復提供了可行方案
缺點
導致系統增加過多具體命令類,因爲對每個請求接收者調用都需要設計一個具體命令類
命令模式適用環境
- 系統需要將請求調用者和請求接收者解耦
- 系統需要在不同的時間執行請求
- 系統需要支持命令的撤銷和恢復
- 系統需要將一組操作組合成宏命令
迭代器模式
用於對一個聚合對象進行遍歷,可以將數據的遍歷從聚合對象中分離出來,聚合對象只負責存儲數據,而遍歷數據有迭代器完成
迭代器模式定義:提供一種方法順序訪問一個聚合對象中的各個元素,而不用暴露該對象的內部表示
迭代器數據結構
- 抽象迭代器(Iterator):定義訪問和遍歷元素的接口
- 具體迭代器(ConcereteIterator):實現抽象迭代器,通過遊標記錄在集合對象所處的位置
- 抽象聚合類(Aggrate):用於存儲和管理元素對象,充當抽象迭代器工廠角色
- 具體聚合類(ConcereteAggrate):實現抽象聚合類中創建迭代器的方法
迭代器模式的實現
## 定義抽象迭代器
public interface Interator{
public void first();
public void next();
public boolean hasNext();
}
## 具體迭代器
public class ConcreteInterator implements Interator{
private ConcreteAggrage objects; //維持一個對具體聚合對象的引用
private int cursor; //遊標,記錄當前訪問位置
public ConcreteInterator(ConcreteAggrate objects){
this.objects=objects;
}
public void first(){};
public void next(){};
public boolean hasNext(){};
}
## 定義存儲數據的聚合對象
public interface Aggrate{
Interator createInterator();
}
## 定義具體迭代器
public class ConcreteAggrate implements Aggrate{
public Interagor createInterator(){
return new ConcreteInterator(this);
}
}
內部類實現迭代器
將迭代器設知道聚合類的內部
public abstract class AbstractlList<E> extends AbstractCollection<E> implements List<E>{
private class Int implements Interator<E>{
int cursor=0;
..
}
}
java內置迭代器
在每一個next()方法被調用時,迭代器遊標由元素1——>元素2,因此next方法返回元素2的引用
迭代器優缺點
優點
- 客戶端可以通過不同的方式遍歷一個聚合對象(更換迭代器),在同一個聚合對象上可定義多種遍歷方式
- 系統簡化了聚合類的設計
- 增加聚合類和迭代器都無需修改現有代碼
缺點
增加新得聚合類需要增加對應迭代器類,類的個數成對增加
迭代器適用環境
- 客戶端訪問一個聚合對象,而無需暴露它的內部表示
- 系統需要爲聚合對象提供多種管理方式
- 客戶端使用統一接口遍歷聚合對象,而且實現類爲其提供不同實現
觀察者模式
定義對象之間的額一種一對多的依賴關係,使得每當一個對象的裝填發生變化時,其他依賴對象都得到通知並被自動更新。類似發佈訂閱模式。
觀察者模式數據結構
- 目標(Subject):它是被觀察的對象,定義了一個觀察者的集合,提供一系列增刪觀察者對象的方法,同時有定義了通知方法notify()
- 具體目標(ConcreteSubject):封裝了數據,當數據發送改變時將向它的各個觀察者發出通知
- 觀察者(Observer):觀察者對觀察目標的改變做出反應,一般聲明更新數據的方法update
- 具體觀察者(ConcreteObserver):維護一個具體目標的引用,他存儲具體觀察者的有關狀態
觀察者模式實現
觀察者描述瞭如何建立 對象和對象之間的依賴關係,以及如何構造滿足這種需求的系統。
目標——>觀察者
## 定義抽象目標類
public abstract class Subject{
//存儲所有觀察者對象
protected List<Observer> observers=new ArrayList();
//註冊觀察者
public void attach(Observer observer){
observers.add(observers);
}
//註銷觀察者
public void detach(Observer observer){
observers.remove(observer);
}
//通知方法
public abstract void notify();
}
## 具體目標類
public class ConcreteSubject extends Subject(){
public void notify(){
//遍歷觀察者集合,調用每個觀察者的響應方法
for(Object obj:observers){
(Observers)obj.update();
}
}
}
## 抽象觀察者
public interface Observer{
//定義響應方法
public void update();
}
## 具體觀察者
public class ConcreteObserver implements Observer{
public void update(){
//具體響應代碼
}
}
JDK對觀察者模式的支持
java.util包中提供了一個Observable類以及Observe接口,它們構成了JDK對觀察者模式支持的基礎
目標——>觀察者
//觀察者
public interface Observer {
void update(Observable o, Object arg); //當觀察目標發生變化,此方法會被調用
}
//目標
public class Observable {
private boolean changed = false;
private Vector<Observer> obs = new Vector(); //存儲目標的觀察者對象
public synchronized void addObserver(Observer var1) { //增加觀察者
if (var1 == null) {
throw new NullPointerException();
} else {
if (!this.obs.contains(var1)) {
this.obs.addElement(var1);
}
}
}
public synchronized void deleteObserver(Observer var1) { //刪除觀察者
this.obs.removeElement(var1);
}
public void notifyObservers() { //通知觀察者
this.notifyObservers((Object)null);
}
public void notifyObservers(Object var1) { //通知觀察者
Object[] var2;
synchronized(this) {
if (!this.changed) {
return;
}
var2 = this.obs.toArray();
this.clearChanged();
}
for(int var3 = var2.length - 1; var3 >= 0; --var3) {
((Observer)var2[var3]).update(this, var1);
}
}
public synchronized void deleteObservers() { //刪除觀察者
this.obs.removeAllElements();
}
protected synchronized void setChanged() { //表示目標狀態發生了變化
this.changed = true;
}
protected synchronized void clearChanged() { //目標對象不再變化,目標已經通知了所有觀察者
this.changed = false;
}
public synchronized boolean hasChanged() { //判斷目標是否變化
return this.changed;
}
public synchronized int countObservers() { //返回目標的觀察者數目
return this.obs.size();
}
}
觀察者模式與Java事件的處理
JDK1.0的事件模型是基於職責鏈模式,但是這種模型不適於複雜系統
JDK1.1的事件模型是基於觀察者模式的委派事件模型=引發的事件不由引發事件的對象自己處理,而是委派給獨立事件處理對象負責。
委派事件模型={事件源+事件+事件監聽器}:
事件源充當目標角色:發佈事件
事件監聽器充當觀察者角色 :向目標訂閱感興趣的事件
事件對象封裝事件相關信息
觀察者與MVC
MVC是一種架構模型,包含三個角色:模型+視圖+控制器
模型對應於觀察目標
視圖對應於觀察者
控制器充當兩者之間的中介者
當模型層的數據發生改變時,視圖層的數據將自動改變其顯示內容。
java事件原理示例
單擊按鈕流程
- 單擊按鈕,觸發ActionEvent類型的事件,產生ActionEvent類型的事件對象
- 將ActionEvent事件對象傳遞給事件監聽器對象,開發人員實現ActionListener接口,重寫actionPerformed方法處理事件
- 開發人員將ActionListener接口的實現類註冊到按鈕中
- JVM觸發事件調用按鈕的方法,內部調用事件監聽器的事件處理方法
自定義GUI組件:包含兩個文本框和兩個按鈕的登陸組件LoginBean
## 自定義事件,AWT模型繼承EventObject
public class LoginEvent{
String username;
String password;
}
## 自定義登陸組件(目標類) 一對一觀察
public class LoginBean{
LoginEventListener listener;
LoginEvent event;
//
public void addLoginEventListener(LoginEventListener listener){};
public void fireLoginEvent(Object obj,String username,String password){
//實例化事件對象
//將事件傳遞給觀察者對象 傳遞對象—通過方法參數
//調用觀察者對象的響應方法vlidateLogin(event)
};
}
## 自定義抽象觀察者
public abstract class LoginEventListener{
validateLogin(LoginEvent event); //事件處理函數
}
## 自定義具體觀察者
public class LoginValidateA{} //爲事件提供不同實現
public class LoginValidateB() //爲事件提供不同實現
觀察者模式優缺點
凡是使用1對1,1對多的交互場景都可以使用觀察者模式
優點
- 系統定義了完整的消息更新傳遞機制,抽象了更新接口
- 系統支持廣播通信,簡化1對多系統設計難度
- 增加新得具體觀察者無需修改原有代碼,符合開閉原則
缺點
a)若目標擁有很多觀察者,將所有觀察者通知到浪費時間
b) 若觀察者和觀察目標之間存在循環依賴,則可能導致系統奔潰
c) 觀察者不知道目標是怎麼發生變化的
觀察者使用場景
- 抽象模型有兩個方便,一個依賴於另一個,將兩個方面封裝在獨立對象使其可獨立擴展
- 需要在系統創建一個觸發鏈
- 一個對象的改變將導致一個或多個對象也發生改變,而並不知道具體有多少對象發生改變,也不知道這些對象是誰
策略模式
通過算法定義和算法使用的分離,實現了算法的自由切換或新增,支持用戶從算法族中更換算法或新增算法
策略模式定義:定義一系列算法,將每一個算法封裝起來,並可隨意切換或新增
策略模式數據結構
- 環境類(Context):定義採用哪種算法的邏輯
- 抽象策略類(Stragtegy):爲支持的算法聲明瞭抽象方法
- 具體策略類(ConcreteStrategy):實現了某一種算法實現
策略模式實現
## 定義抽象算法
public abstract class AbstractStrategy{
public abstract void algorithm(); //聲明抽象算法
}
## 定義具體抽象算法
public class ConcreteStrategyA extends AbstractStrategy{
public void algorithm(){
//算法a
};
}
## 定義環境類,決定使用哪種算法的羅
public class Context{
private AbstractStrategy strategy; //維持一個抽象策略的引用
public void setStrategy(AbstractStrategy strategy){
this.strategy=strategy;
}
public void algorithm(){
strategy.algorithm(); //調用具體策略類的算法
}
}
策略模式優點
通過關聯代替繼承
優點:
- 系統新增算法不會修改原有代碼
- 系統提供了關係相關算法族的方法
- 客戶端避免了多重條件選擇語句,把選擇和算法解耦,符合單一原則
缺點:
a) 客戶端必須知道所有策略類,並自主選擇哪一種策略類
b) 導致系統增加很多具體策略類
c) 無法同時使用多個策略類
策略模式適用環境
- 系統需要在幾種算法選擇一種
- 一個對象有很多種行爲,避免採用多重條件判斷
- 系統不希望用戶知道算法的細節
模板方法模式
模板方法模式定義:定義一個操作中算法的框架,而將一些步驟延遲到子類中。模範方法模式可以在不改變一個算法的結構的基礎上重定義該算法的某些特定步驟
模板方法數據結構
- 抽象類(AbstractClass):定義一系列基本操作,每一個基本操作對應算法的一個步驟,子類可重寫這些步驟;在抽象類中實現了一個模板方法,將基本操作方法組合形成一個總算法框架
- 抽象子類(ConcreteClass):實現父類中定義的一些特性算法步驟
模板方法的實現
## 實現模板方法
public abstract class AbstractClass{
//模板方法
public void templateMethod(){
operation1();
operation2();
operation3();
}
public void operation1(){};//具體方法
public abstract void operation2(){};//抽象方法
public void operation3(){};//鉤子方法
}
## 具體子類 多態性:子類對象在運行時將覆蓋父類對象
public class ConcreteClass extends AbstractClass{
public void operation1(){
//重寫操作1
}
public void operation2(){
//重寫操作2
}
}
模板模式優缺點
優點
- 系統中通過父類形式化定義一個算法框架,通過子類實現具體細節
- 系統中可以通過子類覆蓋鉤子函數,來決定某一特定步驟是否需要執行
缺點
a) 模板方法爲每一個基本方法的不同實現都提供一個子類,導致個數急劇增加
模板模式適用環境
- 對一些複雜算法進行分割,將算法中固定不變的步驟設計爲模板方法,而一些可以改變的細節由子類來實現
- 系統中子類的公共部分需要抽離到父類
- 系統需要通過子類來決定父類中某個步驟是否執行,實現子類對父類的反向控制