摘要:但是發出者并不清楚到底最終那個對象會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。因為訪問者模式使得算法操作增加變得容易。訪問者模式將有關行為集中到一個訪問者對象中,其改變不影響系統數據結構。
總體分為3大類:
創建型模式 (5種):工廠方法、抽象工廠、單例、建造者、原型
結構型模式(7種):適配器、裝飾器、代理、外觀、橋接、組合、享元
行為型模式(11種):策略、模板方法、觀察者、迭代子、責任鏈、命令、備忘錄、狀態、訪問者、中介者、解釋器
其它(2種):并發型、線程池
先來看看這11種模式的關系:
第一類:通過父類與子類的關系進行實現。
第二類:兩個類之間。
第三類:類的狀態。
第四類:通過中間類
定義一系列可以相互替換的算法,并將每個算法封裝起來。設計一個接口為實現類提供統一的方法,設計一個抽象類(可有可無,屬于輔助類)提供輔助函數:
public interface ICalculator { int calculate(String exp); }
輔助類:
public abstract class AbstractCalculator { public int[] split(String exp, String opt){ String array[] = exp.split(opt); int arrayInt[] = new int[2]; arrayInt[0] = Integer.parseInt(array[0]); arrayInt[1] = Integer.parseInt(array[1]); return arrayInt; } }
三個實現類:
public class Plus extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp,"+"); return arrayInt[0]+arrayInt[1]; } }
public class Minus extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp,"-"); return arrayInt[0]-arrayInt[1]; } }
public class Multiply extends AbstractCalculator implements ICalculator { @Override public int calculate(String exp) { int arrayInt[] = split(exp,"*"); return arrayInt[0]*arrayInt[1]; } }
簡單的測試類:
public class StrategyTest { public static void main(String[] args) { String exp = "2+8"; ICalculator cal = new Plus(); int result = cal.calculate(exp); System.out.println(result); } }
策略模式多用在算法決策系統中,用戶只需要決定用哪個算法即可。
模板方法(Template Method)抽象類中有一個主方法,再定義n個方法(可以是抽象的,也可以是實際的方法),定義一個類繼承該抽象類,重寫抽象方法,通過調用抽象類,實現對子類的調用:
就是在 AbstractCalculator 類中定義一個主方法 calculate,calculate()調用 spilt()等,Plus 和Minus 分別繼承 AbstractCalculator 類,通過對 AbstractCalculator 的調用實現對子類的調用:
public abstract class AbstractCalculator { /*主方法,實現對本類其它方法的調用*/ public final int calculate(String exp, String opt){ int array[] = split(exp,opt); return calculate(array[0],array[1]); } /*被子類重寫的方法*/ protected abstract int calculate(int num1, int num2); private int[] split(String exp, String opt) { String[] array = exp.split(opt); int[] arrayInt = new int[2]; arrayInt[0] = Integer.parseInt(array[0]); arrayInt[1] = Integer.parseInt(array[1]); return arrayInt; } }
public class Plus extends AbstractCalculator { @Override protected int calculate(int num1, int num2) { return num1 + num2; } }
測試類:
public class StrategyTest { public static void main(String[] args) { String exp = "8+8"; AbstractCalculator cal = new Plus(); int result = cal.calculate(exp,"+"); System.out.println(result); } }
輸出:16
二、類之間關系 觀察者(Observer)包括這個模式在內的接下來的四個模式,都是類和類之間的關系,不涉及到繼承,學的時候應該 記得歸納,記得本文最開始的那個圖。觀察者模式很好理解,類似于郵件訂閱和 RSS 訂閱,當我們瀏覽一些博客或 wiki 時,經常會看到 RSS 圖標,就這的意思是,當你訂閱了該文章,如果后續有更新,會及時通知你。其實,簡單來講就一句話:當一個對象變化時,其它依賴該對象的對象都會收到通知,并且隨著變化!對象之間是一種一對多的關系。先來看看關系圖:
我解釋下這些類的作用:MySubject 類就是我們的主對象,Observer1 和 Observer2 是依賴于MySubject 的對象,當 MySubject 變化時,Observer1 和 Observer2 必然變化。AbstractSubject類中定義著需要監控的對象列表,可以對其進行修改:增加或刪除被監控對象,且當 MySubject變化時,負責通知在列表內存在的對象。我們看實現代碼:
一個 Observer 接口:
public interface Observer { void update(); }
兩個實現類:
public class Observer1 implements Observer { @Override public void update() { System.out.println("observer1 has received!"); } }
public class Observer2 implements Observer{ @Override public void update() { System.out.println("observer2 has received!"); } }
Subject 接口及實現類:
public interface Subject { /*增加觀察者*/ void add(Observer observer); /*刪除觀察者*/ void del(Observer observer); /*通知所有的觀察者*/ void notifyObservers(); /*自身的操作*/ void operation(); }
public abstract class AbstractSubject implements Subject { private Vectorvector = new Vector (); @Override public void add(Observer observer) { vector.add(observer); } @Override public void del(Observer observer) { vector.remove(observer); } @Override public void notifyObservers() { Enumeration enumo = vector.elements(); while(enumo.hasMoreElements()){ enumo.nextElement().update(); } } }
public class MySubject extends AbstractSubject { @Override public void operation() { System.out.println("update self!"); notifyObservers(); } }
測試類:
public class ObserverTest { public static void main(String[] args) { MySubject sub = new MySubject(); sub.add(new Observer1()); sub.add(new Observer2()); sub.operation(); } }
輸出:
update self!
observer1 has received!
observer2 has received!
順序訪問集合中的對象,一般來說,集合中非常常見,如果對集合類比較熟悉的話,理解本模式會十分輕松。這句話包含兩層意思:一是需要遍歷的對象,即聚集對象,二是迭代器對象,用于對聚集對象進行遍歷訪問。我們看下關系圖
這個思路和我們常用的一模一樣,MyCollection 中定義了集合的一些操作,MyIterator 中定義了一系列迭代操作,且持有 Collection 實例,我們來看看實現代碼:
兩個接口 :
public interface Collection { Iterator iterator(); /*取得集合元素*/ Object get(int i); /*取得集合大小*/ int size(); }
public interface Iterator { //前移 Object previous(); //后移 Object next(); boolean hasNext(); //取得第一個元素 Object first(); }
兩個實現:
public class MyCollection implements Collection { public String string[] = {"A","B","C","D","E"}; @Override public Iterator iterator() { return new MyIterator( this ); } @Override public Object get(int i) { return string[i]; } @Override public int size() { return string.length; } }
public class MyIterator implements Iterator { private Collection collection; private int pos = -1; public MyIterator(Collection collection) { this.collection = collection; } @Override public Object previous() { if (pos > 0) { pos--; } return collection.get(pos); } @Override public Object next() { if (pos < collection.size() - 1) { pos++; } return collection.get(pos); } @Override public boolean hasNext() { if (pos < collection.size() - 1) { return true; }else { return false; } } @Override public Object first() { pos = 0; return collection.get(pos); } }
測試類:
public class Test { public static void main(String[] args) { MyCollection collection = new MyCollection(); Iterator it = collection.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } }
輸出:A B C D E
此處我們貌似模擬了一個集合類的過程,感覺是不是很爽?其實 JDK 中各個類也都是這些基本的東西,加一些設計模式,再加一些優化放到一起的,只要我們把這些東西學會了,掌握好了,我們也可以寫出自己的集合類,甚至框架!
接下來我們將要談談責任鏈模式,有多個對象,每個對象持有對下一個對象的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一對象決定處理該請求。但是發出者并不清楚到底最終那個對象會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。先看看關系圖:
Abstracthandler 類提供了 get 和 set 方法,方便 MyHandle 類設置和修改引用對象,MyHandle類是核心,實例化后生成一系列相互持有的對象,構成一條鏈 。
public interface Handler { void operator(); }
public abstract class AbstractHandler { private Handler handler; public Handler getHandler() { return handler; } public void setHandler(Handler handler) { this.handler = handler; } }
public class MyHandler extends AbstractHandler implements Handler { private String name; public MyHandler(String name) { this.name = name; } @Override public void operator() { System.out.println(name + "deal!"); if (null != getHandler()) { getHandler().operator(); } } }
public class Test { public static void main(String[] args) { MyHandler h1 = new MyHandler("h1"); MyHandler h2 = new MyHandler("h2"); MyHandler h3 = new MyHandler("h3"); h1.setHandler(h2); h2.setHandler(h3); h1.operator(); } }
輸出:
h1deal!
h2deal!
h3deal!
此處強調一點就是,鏈接上的請求可以是一條鏈,可以是一個樹,還可以是一個環,模式本身不約束這個,需要我們自己去實現,同時,在一個時刻,命令只允許由一個對象傳給另一個對象,而不允許傳給多個對象 。
命令模式很好理解,舉個例子,司令員下令讓士兵去干件事情,從整個事情的角度來考慮,司令員的作用是,發出口令,口令經過傳遞,傳到了士兵耳朵里,士兵去執行。這個過程好在,三者相互解耦,任何一方都不用去依賴其他,只需要做好自己的事兒就行,司令員要的是結果,不會去關注到底士兵是怎么實現的。我們看看關系圖:
public interface Command { void exe(); }
public class MyCommand implements Command { private Receiver receiver; public MyCommand(Receiver receiver) { this.receiver = receiver; } @Override public void exe() { receiver.action(); } }
public class Receiver { public void action() { System.out.println("command received!"); } }
public class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void action() { command.exe(); } }
public class Test { public static void main(String[] args) { Receiver receiver = new Receiver(); MyCommand cmd = new MyCommand(receiver); Invoker invoker = new Invoker(cmd); invoker.action(); } }
輸出:command received!
命令模式的目的就是達到命令的發出者和執行者之間解耦,實現請求和執行分開,熟悉 Struts 的同學應該知道,Struts 其實就是一種將請求和呈現分離的技術,其中必然涉及命令模式的思想!
其實每個設計模式都是很重要的一種思想,看上去很熟,其實是因為我們在學到的東西中都有涉及,盡管有時我們并不知道,其實在 Java 本身的設計之中處處都有體現,像 AWT、JDBC、集合類、IO 管道或者是 Web 框架,里面設計模式無處不在。因為我們篇幅有限,很難講每一個設計模式都講的很詳細,不過我會盡我所能,盡量在有限的空間和篇幅內,把意思寫清楚了,更好讓大家明白。
主要目的是保存一個對象的某個狀態,以便在適當的時候恢復對象,個人覺得叫備份模式更形象些,通俗的講下:假設有原始類 A,A 中有各種屬性,A 可以決定需要備份的屬性,備忘錄類 B 是用來存儲 A 的一些內部狀態,類 C 呢,就是一個用來存儲備忘錄的,且只能存儲,不能修改等操作。做個圖來分析一下:
Original 類是原始類,里面有需要保存的屬性 value 及創建一個備忘錄類,用來保存 value 值。Memento 類是備忘錄類,Storage 類是存儲備忘錄的類,持有 Memento 類的實例,該模式很好理解。直接看源碼:
public class Original { private String value; public Original(String value) { this.value = value; } public Memento createMemento() { return new Memento(value); } public void restoreMemento(Memento memento) { this.value = memento.getValue(); } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
public class Memento { private String value; public Memento(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
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 Test { public static void main(String[] args) { // 創建原始類 Original origi = new Original("egg"); // 創建備忘錄 Storage storage = new Storage(origi.createMemento()); // 修改原始類的狀態 System.out.println("初始化狀態為:" + origi.getValue()); origi.setValue("niu"); System.out.println("修改后的狀態為:" + origi.getValue()); // 回復原始類的狀態 origi.restoreMemento(storage.getMemento()); System.out.println("恢復后的狀態為:" + origi.getValue()); } }
輸出:
初始化狀態為:egg
修改后的狀態為:niu
恢復后的狀態為:egg
簡單描述下:新建原始類時,value 被初始化為 egg,后經過修改,將 value 的值置為 niu,最后倒數第二行進行恢復狀態,結果成功恢復了。其實我覺得這個模式叫“備份-恢復”模式最形象。
核心思想就是:當對象的狀態改變時,同時改變其行為,很好理解!就拿 QQ 來說,有幾種狀態,在線、隱身、忙碌等,每個狀態對應不同的操作,而且你的好友也能看到你的狀態,所以,狀態模式就兩點:1、可以通過改變狀態來獲得不同的行為。2、你的好友能同時看到你的變化。看圖:
public class State { private String value; public void method1() { System.out.println("execute the first opt!"); } public void method2() { System.out.println("execute the second opt!"); } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
public class Context { private State state; public void method() { if (state.getValue().equals("state1")) { state.method1(); } else if (state.getValue().equals("state2")) { state.method2(); } } public Context(State state) { this.state = state; } public State getState() { return state; } public void setState(State state) { this.state = state; } }
測試類:
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(); } }
輸出:
execute the first opt!
execute the second opt!
根據這個特性,狀態模式在日常開發中用的挺多的,尤其是做網站的時候,我們有時希望根據對象的某一屬性,區別開他們的一些功能,比如說簡單的權限控制等 。
訪問者模式把數據結構和作用于結構上的操作解耦合,使得操作集合可相對自由地演化。訪問者模式適用于數據結構相對穩定算法又易變化的系統。因為訪問者模式使得算法操作增加變得容易。若系統數據結構對象易于變化,經常有新的數據對象增加進來,則不適合使用訪問者模式。訪問者模式的優點是增加操作很容易,因為增加操作意味著增加新的訪問者。訪問者模式將有關行為集中到一個訪問者對象中,其改變不影響系統數據結構。其缺點就是增加新的數據結構很困難。—— From 百科
簡單來說,訪問者模式就是一種分離對象數據結構與行為的方法,通過這種分離,可達到為一個被訪問者動態添加新的操作而無需做其它的修改的效果。簡單關系圖:
public interface Visitor { void visit(Subject sub); }
public class MyVisitor implements Visitor { @Override public void visit(Subject sub) { System.out.println("visit the subjcet:" + sub.getSubject()); } }
Subject 類,accept 方法,接受將要訪問它的對象,getSubject()獲取將要被訪問的屬性,
public interface Subject { void accept(Visitor visitor); String getSubject(); }
public class MySubject implements Subject { @Override public void accept(Visitor visitor) { visitor.visit(this); } @Override public String getSubject() { return "love"; } }
測試類:
public class Test { public static void main(String[] args) { Visitor visitor = new MyVisitor(); Subject sub = new MySubject(); sub.accept(visitor); } }
輸出:visit the subject:love
該模式適用場景:如果我們想為一個現有的類增加新功能,不得不考慮幾個事情:1、新功能會不會與現有功能出現兼容性問題?2、以后會不會再需要添加?3、如果類不允許修改代碼怎么辦?面對這些問題,最好的解決方法就是使用訪問者模式,訪問者模式適用于數據結構相對穩定的系統,把數據結構和算法解耦,
中介者模式也是用來降低類類之間的耦合的,因為如果類類之間有依賴關系的話,不利于功能的拓展和維護,因為只要修改一個對象,其它關聯的對象都得進行修改。如果使用中介者模式,只需關心和 Mediator 類的關系,具體類類之間的關系及調度交給 Mediator 就行,這有點像spring 容器的作用。先看看圖:
User 類統一接口,User1 和 User2 分別是不同的對象,二者之間有關聯,如果不采用中介者模式,則需要二者相互持有引用,這樣二者的耦合度很高,為了解耦,引入了 Mediator 類,提供統一接口,MyMediator 為其實現類,里面持有 User1 和 User2 的實例,用來實現對 User1和 User2 的控制。這樣 User1 和 User2 兩個對象相互獨立,他們只需要保持好和 Mediator 之間的關系就行,剩下的全由 MyMediator 類來維護!基本實現:
public interface Mediator { void createMediator(); void workAll(); }
public class MyMediator implements Mediator { private User user1; private User user2; public User getUser1() { return user1; } public User getUser2() { return user2; } @Override public void createMediator() { user1 = new User1(this); user2 = new User2(this); } @Override public void workAll() { user1.work(); user2.work(); } }
public abstract class User { private Mediator mediator; public abstract void work(); public Mediator getMediator() { return mediator; } public User(Mediator mediator) { this.mediator = mediator; } }
public class User1 extends User { public User1(Mediator mediator) { super(mediator); } @Override public void work() { System.out.println("user1 exe!"); } }
public class User2 extends User { public User2(Mediator mediator) { super(mediator); } @Override public void work() { System.out.println("user2 exe!"); } }
測試類:
public class Test { public static void main(String[] args) { MyMediator mediator = new MyMediator(); mediator.createMediator(); mediator.workAll(); } }
輸出:
user1 exe!
user2 exe!
解釋器模式是我們暫時的最后一講,一般主要應用在 OOP 開發中的編譯器的開發中,所以適用面比較窄。
Context 類是一個上下文環境類,Plus 和 Minus 分別是用來計算的實現,代碼如下:
public interface Expression { int interpret(Context context); }
public class Plus implements Expression { @Override public int interpret(Context context) { return context.getNum1() + context.getNum2(); } }
public class Minus implements Expression { @Override public int interpret(Context context) { return context.getNum1() - context.getNum2(); } }
public class Context { private int num1; private int num2; public Context(int num1, int num2) { this.num1 = num1; this.num2 = num2; } public int getNum1() { return num1; } public void setNum1(int num1) { this.num1 = num1; } public int getNum2() { return num2; } public void setNum2(int num2) { this.num2 = num2; } }
測試類:
public class Test { public static void main(String[] args) { // 計算 9+2-8 的值 int result = new Minus().interpret((new Context(new Plus().interpret(new Context(9, 2)), 8))); System.out.println(result); } }
最后輸出正確的結果:3。
基本就這樣,解釋器模式用來做各種各樣的解釋器,如正則表達式等的解釋器等等!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71045.html
摘要:當然,除了讓我們顯得更加專業之外,在自己所學習或者工作的項目中,適當合理的使用設計模式,能夠給項目帶來很大的好處。 簡單說兩句 本文首發公眾號【一名打字員】 對不住各位老鐵了,年前說好要更幾波JAVA的東西,又偷懶了,沒辦法,在這里用小錘錘偷偷錘了自己幾下。由于工作原因,更新時間不定,各位老鐵有問題可以私聊我哈。 對于初學者或者是正在向中高級的Java程序猿(打字員)來說,時刻梳理自己...
摘要:推文用設計模式解構三國是一種什么體驗行為型設計模式一策略模式工廠模式優化結構狀態模式隨著狀態改變而改變行為。推文狀態機與狀態模式責任鏈模式多個對象依次處理請求前者指定后者。代理模式代理針對一個對象,為了增加控制等中介雙方都是多個,為了解耦。 策略模式 選擇使用封裝好的一系列算法,可相互替換。 類比:商店[Context]買完衣服買單[Stratege](現金[Concrete Stra...
摘要:類共享,因此需要實現中的所有抽象方法,如果有的具體策略類比較簡單,但還是必須要去實現它的抽象方法,因此會增加不必要的開銷參考設計模式十八策略模式對象行為型深入面向對象模式與實踐第版 因為最近在學策略模式,所以想先跳過創建型設計模式中得適配器模式 定義 策略模式,顧名思義,就是提供多個策略的模式,用戶在不同的情況下可以選擇不同的策略,比如商場的打折策略(不同節假日不同的折扣方式),旅游出...
摘要:設計模式的類別設計模式一共分為種類型,共種。屬于結構型的設計模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。問題描述了應該在何時使用設計模式。解決方案描述了設計的組成成分,它們之間的相互關系及各自的職責和協作方式。 設計模式概述 1. 設計模式是什么 我們在平時編寫代碼的過程中,會遇到各種各樣的問題,細想一下很多問題的解決思路大致一樣的,這時候你就可以把解決問題的思路整...
閱讀 2772·2021-11-19 11:30
閱讀 3058·2021-11-15 11:39
閱讀 1782·2021-08-03 14:03
閱讀 1985·2019-08-30 14:18
閱讀 2043·2019-08-30 11:16
閱讀 2149·2019-08-29 17:23
閱讀 2597·2019-08-28 18:06
閱讀 2533·2019-08-26 12:22