設計模式;
一個程序員對設計模式的理解: “不懂”為什么要把很簡單的東西搞得那么復雜。后來隨著軟件開發(fā)經驗的增加才開始明白我所看到的“復雜”恰恰就是設計模式的精髓所在,我所理解的“簡單”就是一把鑰匙開一把鎖的模式,目的僅僅是著眼于解決現在的問題,而設計模式的“復雜”就在于它是要構造一個“萬能鑰匙”,目的是提出一種對所有鎖的開鎖方案。在真正理解設計模式之前我一直在編寫“簡單”的代碼. 這個“簡單”不是功能的簡單,而是設計的簡單。簡單的設計意味著缺少靈活性,代碼很鋼硬,只在這個項目里有用,拿到其它的項目中就是垃圾,我將其稱之為“一次性代碼”。 -->要使代碼可被反復使用,請用'設計模式'對你的代碼進行設計.
很多我所認識的程序員在接觸到設計模式之后,都有一種相見恨晚的感覺,有人形容學習了設計模式之后感覺自己好像已經脫胎換骨,達到了新的境界,還有人甚至把是否了解設計模式作為程序員劃分水平的標準。
我們也不能陷入模式的陷阱,為了使用模式而去套模式,那樣會陷入形式主義。我們在使用模式的時候,一定要注意模式的意圖(intent),而不 要過多的去關注模式的實現細節(jié),因為這些實現細節(jié)在特定情況下,可能會發(fā)生一些改變。不要頑固地認為設計模式一書中的類圖或實現代碼就代表了模式本身。
設計原則:(重要) 1. 邏輯代碼獨立到單獨的方法中,注重封裝性--易讀,易復用。 不要在一個方法中,寫下上百行的邏輯代碼。把各小邏輯代碼獨立出來,寫于其它方法中,易讀其可重復調用。 2. 寫類,寫方法,寫功能時,應考慮其移植性,復用性:防止一次性代碼! 是否可以拿到其它同類事物中應該?是否可以拿到其它系統(tǒng)中應該? 3. 熟練運用繼承的思想: 找出應用中相同之處,且不容易發(fā)生變化的東西,把它們抽取到抽象類中,讓子類去繼承它們; 繼承的思想,也方便將自己的邏輯建立于別人的成果之上。如ImageField extends JTextField; 熟練運用接口的思想: 找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。 把很簡單的東西搞得那么復雜,一次性代碼,設計模式優(yōu)勢的實例說明:(策略模式) 說明: 模擬鴨子游戲的應用程序,要求:游戲中會出現各種顏色外形的鴨子,一邊游泳戲水,一邊呱呱叫。 第一種方法:(一次性代碼)
直接編寫出各種鴨子的類:MallardDuck//野鴨,RedheadDuck//紅頭鴨,各類有三個方法: quack():叫的方法 swim():游水的方法 display():外形的方法 第二種方法:運用繼承的特性,將其中共同的部分提升出來,避免重復編程。
即:設計一個鴨子的超類(Superclass),并讓各種鴨子繼承這個超類。 public class Duck{ public void quack(){ //呱呱叫 System.out.println("呱呱叫"); } public void swim(){ //游泳 System.out.println(" 游泳"); } public abstratact void display(); /*因為外觀不一樣,讓子類自己去決定了。*/ } 對于它的子類只需簡單的繼承就可以了,并實現自己的display()方法。
//野鴨 public class MallardDuck extends Duck{ public void display(){ System.out.println("野鴨的顏色..."); } } //紅頭鴨 public class RedheadDuck extends Duck{ public void display(){ System.out.println("紅頭鴨的顏色..."); } } 不幸的是,現在客戶又提出了新的需求,想讓鴨子飛起來。這個對于我們OO程序員,在簡單不過了,在超類中在加一
個方法就可以了。
public class Duck{ public void quack(){ //呱呱叫 System.out.println("呱呱叫"); } public void swim(){ //游泳 System.out.println(" 游泳"); } public abstract void display(); /*因為外觀不一樣,讓子類自己去決定了。*/ public void fly(){ System.out.println("飛吧!鴨子"); } } 對于不能飛的鴨子,在子類中只需簡單的覆蓋。 //殘廢鴨 public class DisabledDuck extends Duck{ public void display(){ System.out.println("殘廢鴨的顏色..."); } public void fly(){ //覆蓋,變成什么事都不做。 } } 其它會飛的鴨子不用覆蓋。 這樣所有的繼承這個超類的鴨子都會fly了。但是問題又出來了,客戶又提出有的鴨子會飛,有的不能飛。
>>>>>>點評:
對于上面的設計,你可能發(fā)現一些弊端,如果超類有新的特性,子類都必須變動,這是我們開發(fā)最不喜歡看到的,一個類變讓另一個類也跟著變,這有點不符合OO設計了。這樣很顯然的耦合了一起。利用繼承-->耦合度太高了. 第三種方法:
用接口改進. 我們把容易引起變化的部分提取出來并封裝之,來應付以后的變法。雖然代碼量加大了,但可用性提高了,耦合度也降低了。 我們把Duck中的fly方法和quack提取出來。
public interface Flyable{ public void fly(); } public interface Quackable{ public void quack(); } 最后Duck的設計成為: public class Duck{ public void swim(){ //游泳 System.out.println(" 游泳"); } public abstract void display(); /*因為外觀不一樣,讓子類自 己去決定了。*/ } 而MallardDuck,RedheadDuck,DisabledDuck 就可以寫成為: //野鴨 public class MallardDuck extends Duck implements Flyable,Quackable{ public void display(){ System.out.println("野鴨的顏色..."); } public void fly(){ //實現該方法 } public void quack(){ //實現該方法 } } //紅頭鴨 public class RedheadDuck extends Duck implements Flyable,Quackable{ public void display(){ System.out.println("紅頭鴨的顏色..."); } public void fly(){ //實現該方法 } public void quack(){ //實現該方法 } } //殘廢鴨 只實現Quackable(能叫不能飛) public class DisabledDuck extends Duck implements Quackable{ public void display(){ System.out.println("殘廢鴨的顏色..."); } public void quack(){ //實現該方法 } } >>>>>>點評:
好處: 這樣已設計,我們的程序就降低了它們之間的耦合。 不足: Flyable和 Quackable接口一開始似乎還挺不錯的,解決了問題(只有會飛到鴨子才實現 Flyable),但是Java接口不具有實現代碼,所以實現接口無法達到代碼的復用。 第四種方法:
對上面各方式的總結:
繼承的好處:讓共同部分,可以復用.避免重復編程. 繼承的不好:耦合性高.一旦超類添加一個新方法,子類都繼承,擁有此方法,
若子類相當部分不實現此方法,則要進行大批量修改.
繼承時,子類就不可繼承其它類了.
接口的好處:解決了繼承耦合性高的問題.
且可讓實現類,繼承或實現其它類或接口.
接口的不好:不能真正實現代碼的復用.可用以下的策略模式來解決.
------------------------- strategy(策略模式) -------------------------
我們有一個設計原則: 找出應用中相同之處,且不容易發(fā)生變化的東西,把它們抽取到抽象類中,讓子類去繼承它們; 找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。 -->important. 現在,為了要分開“變化和不變化的部分”,我們準備建立兩組類(完全遠離Duck類),一個是"fly"相關的,另一個
是“quack”相關的,每一組類將實現各自的動作。比方說,我們可能有一個類實現“呱呱叫”,另一個類實現“吱吱
叫”,還有一個類實現“安靜”。
首先寫兩個接口。FlyBehavior(飛行行為)和QuackBehavior(叫的行為).
public interface FlyBehavior{ public void fly(); } public interface QuackBehavior{ public void quack(); } 我們在定義一些針對FlyBehavior的具體實現。 public class FlyWithWings implements FlyBehavior{ public void fly(){ //實現了所有有翅膀的鴨子飛行行為。 } } public class FlyNoWay implements FlyBehavior{
public void fly(){ //什么都不做,不會飛 } } 針對QuackBehavior的幾種具體實現。 public class Quack implements QuackBehavior{ public void quack(){ //實現呱呱叫的鴨子 } } public class Squeak implements QuackBehavior{ public void quack(){ //實現吱吱叫的鴨子 } } public class MuteQuack implements QuackBehavior{ public void quack(){ //什么都不做,不會叫 } } 點評一:
這樣的設計,可以讓飛行和呱呱叫的動作被其他的對象復用,因為這些行為已經與鴨子類無關了。而我們增加一些新 的行為,不會影響到既有的行為類,也不會影響“使用”到飛行行為的鴨子類。
最后我們看看Duck 如何設計。
public class Duck{ --------->在抽象類中,聲明各接口,定義各接口對應的方法. FlyBehavior flyBehavior;//接口 QuackBehavior quackBehavior;//接口 public Duck(){} public abstract void display(); public void swim(){ //實現游泳的行為 } public void performFly(){ flyBehavior.fly(); -->由于是接口,會根據繼承類實現的方式,而調用相應的方法. } public void performQuack(){ quackBehavior.quack();(); } } 看看MallardDuck如何實現。
----->通過構造方法,生成'飛','叫'具體實現類的實例,從而指定'飛','叫'的具體屬性 public class MallardDuck extends Duck{ public MallardDuck { flyBehavior = new FlyWithWings (); quackBehavior = new Quack(); //因為MallardDuck 繼承了Duck,所有具有flyBehavior 與quackBehavior 實例變量} public void display(){ //實現 } } 這樣就滿足了即可以飛,又可以叫,同時展現自己的顏色了。 這樣的設計我們可以看到是把flyBehavior ,quackBehavior 的實例化寫在子類了。我們還可以動態(tài)的來決定。
我們只需在Duck中加上兩個方法。 在構造方法中對屬性進行賦值與用屬性的setter的區(qū)別:
構造方法中對屬性進行賦值:固定,不可變;
用屬性的setter,可以在實例化對象后,動態(tài)的變化,比較靈活。
public class Duck{ FlyBehavior flyBehavior;//接口 QuackBehavior quackBehavior;//接口 public void setFlyBehavior(FlyBehavior flyBehavior){ this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior { this.quackBehavior= quackBehavior; } } ------------------------- static Factory Method(靜態(tài)工廠) ------------------------- (1) 在設計模式中,Factory Method也是比較簡單的一個,但應用非常廣泛,EJB,RMI,COM,CORBA,Swing中都可以看到此模式 的影子,它是最重要的模式之一.在很多地方我們都會看到xxxFactory這樣命名的類.
(2)
基本概念: FactoryMethod是一種創(chuàng)建性模式,它定義了一個創(chuàng)建對象的接口,但是卻讓子類來決定具體實例化哪一個類. 通常我們將Factory Method作為一種標準的創(chuàng)建對象的方法。 應用方面:
當一個類無法預料要創(chuàng)建哪種類的對象或是一個類需要由子類來指定創(chuàng)建的對象時我們就需要用到Factory Method 模 式了.
-------------------------------- singelton(單例模式) --------------------------------
基本概念: Singleton 是一種創(chuàng)建性模型,它用來確保只產生一個實例,并提供一個訪問它的全局訪問點.對一些類來說,保證只有一個實例是很重要的,比如有的時候,數據庫連接或 Socket 連接要受到一定的限制,必須保持同一時間只能有一個連接的存在. 運用:
在于使用static變量; 創(chuàng)建類對象,一般是在構造方法中,或用一個方法來創(chuàng)建類對象。在這里方法中,加對相應的判斷即可。 單態(tài)模式與共享模式的區(qū)別:
單態(tài)模式與共享模式都是讓類的實例是唯一的。
但單態(tài)模式的實現方式是:
在類的內部.即在構造方法中,或靜態(tài)的getInstace方法中,進行判斷,若實例存在,則直接返回,不進行創(chuàng)建;
共享模式的實現方式是:
每次要用到此實例時,先去此hashtable中獲取,若獲取為空,則生成實例,且將類的實例放在一人hashtable中,若獲取不為空,則直接用此實例。
(2)
實例一: public class Singleton { private static Singleton s; public static Singleton getInstance() { if (s == null) s = new Singleton(); return s; } } // 測試類 class singletonTest { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); if (s1==s2) System.out.println("s1 is the same instance with s2"); else System.out.println("s1 is not the same instance with s2"); } } singletonTest運行結果是:
s1 is the same instance with s2 (3)
實例二: class Singleton { static boolean instance_flag = false; // true if 1 instance public Singleton() { if (instance_flag) throw new SingletonException("Only one instance allowed"); else instance_flag = true; // set flag for 1 instance } } -------------------------------- 觀察者模式(Observer) --------------------------------
(1) 基本概念: 觀察者模式屬于行為型模式,其意圖是定義對象間的一種一對多的依賴關系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。 這一個模式的關鍵對象是目標(Subject)和觀察者(Observer)。一個目標可以有任意數目的依賴它的觀察者,一旦目標的狀態(tài)發(fā)生改變,所有的觀察者都得到通知,作為對這個通知的響應,每個觀察者都將查詢目標以使其狀態(tài)與目標的狀態(tài)同步。
適用場景:
觀察者模式,用于存在一對多依賴關系的對象間,當被依賴者變化時,通知依賴者全部進行更新。因此,被依賴者,應該有添加/刪除依賴者的方法,且可以將添加的依賴者放到一個容器中;且有一個方法去通知依賴者進行更新。
(2)
思想: (一) 建立目標(subject)與觀察者(observer)接口: 目標(subject)接口: 建立一個注冊觀察者對象的接口; public void attach(Observer o); 建立一個刪除觀察者對象的接口; public void detach(Observer o); 建立一個當目標狀態(tài)發(fā)生改變時,發(fā)布通知給觀察者對象的接口; public void notice(); 觀察者(observer)接口:
建立一個當收到目標通知后的更新接口: public void update(); (3)
實例: 老師又電話號碼,學生需要知道老師的電話號碼以便于在合時的時候撥打,在這樣的組合中,老師就是一個被觀察者 (Subject),學生就是需要知道信息的觀察者,當老師的電話號碼發(fā)生改變時,學生得到通知,并更新相應的電話記
錄。
具體實例如下:
Subject代碼: public interface Subject{ public void attach(Observer o); public void detach(Observer o); public void notice(); } Observer代碼:
public interface Observer{ public void update(); } Teacher代碼;
import java.util.Vector; public class Teacher implements Subject{ private String phone; private Vector students; public Teacher(){ phone = ""; students = new Vector(); } public void attach(Observer o){ students.add(o); } public void detach(Observer o){ students.remove(o); } public void notice(){ for(int i=0;i<students.size();i++) ((Observer)students.get(i)).update(); } public void setPhone(String phone){ this.phone = phone; notice(); --關鍵 } public String getPhone(){ return phone; } } Student代碼:
public class Student implements Observer{ private String name; private String phone; private Teacher teacher; public Student(String name,Teacher t){ this.name = name; teacher = t; } public void show(){ System.out.println("Name:"+name+"\nTeacher'sphone:"+phone); } public void update(){ phone = teacher.getPhone(); } } Client代碼: package observer; import java.util.Vector; public class Client{ -->可以只定義目標者,觀察者,另外的vector,只為了輸入結果. public static void main(String[] args){ Vector students = new Vector(); Teacher t = new Teacher(); for(int i= 0 ;i<10;i++){ Student st = new Student("lili"+i,t); students.add(st); t.attach(st); } t.setPhone("88803807"); for(int i=0;i<10;i++) ((Student)students.get(i)).show(); t.setPhone("88808880"); for(int i=0;i<10;i++) ((Student)students.get(i)).show(); } } 總結:Observer模式的最知名的應用是在MVC結構,Observer模式可以很好的應用在文檔和圖表程序的制作中。
------------------------------ 迭代器模式(Iterator) ------------------------------- (1) 基本概念: 迭代器模式屬于行為型模式,其意圖是提供一種方法順序訪問一個聚合對象中得各個元素,而又不需要暴露該對象的 內部表示。
至少可以歷遍first,next,previous,last,isOver,或是歷遍選擇符合某種條件的子元素. (2) 結構: 由一個接口與一個實現類組成. 接口: 主要是定義各歷遍的方法. 實現類: 需要一個計算點private int current=0 ; 以及一個容器Vector,來存在原來的進行歷遍的一團東西;再對接口方法進 行實現.
(3)
實例: Iterator接口: package iterator; public interface Iterator{ /* Item:即是集合中的各對象的類型.若為String,即把所有的ITEM改為String,若為其它自定義的類,則改為各自定義的類 的接口,或類. --->important.
*/ public Item first(); public Item next(); public boolean isDone(); public Item currentItem(); } Controller類實現了Iterator接口。
package iterator; import java.util.Vector; public class Controller implements Iterator{ private int current =0; Vector channel; public Controller(Vector v){ channel = v; } public Item first(){ current = 0; return (Item)channel.get(current); } public Item next(){ current ++; return (Item)channel.get(current); } public Item currentItem(){ return (Item)channel.get(current); } public boolean isDone(){ return current>= channel.size()-1; } } Television接口:
package iterator; import java.util.Vector; public interface Television{ public Iterator createIterator(); } HaierTV類實現了Television接口。 package iterator; import java.util.Vector; public class HaierTV implements Television{ ---對象 private Vector channel; public HaierTV(){ channel = new Vector(); channel.addElement(new Item("channel 1")); --各元素,用VECTOR存放 channel.addElement(new Item("channel 2")); channel.addElement(new Item("channel 3")); channel.addElement(new Item("channel 4")); channel.addElement(new Item("channel 5")); channel.addElement(new Item("channel 6")); channel.addElement(new Item("channel 7")); } public Iterator createIterator(){ return new Controller(channel); --把這個VECTOR放到迭代器中構造方法中去 } } Client客戶端: package iterator; public class Client{ public static void main(String[] args){ Television tv = new HaierTV(); Iterator it =tv.createIterator(); System.out.println(it.first().getName()); while(!it.isDone()){ System.out.println(it.next().getName()); } } } Item類的接口: package iterator; public class Item{ private String name; public Item(String aName){ name = aName; } public String getName(){ return name; } } ------------------------------ 外觀模式(Facade) -------------------------------
(1) 外觀模式屬于結構型模式,Facade模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。 外觀模式的主要用途就是為子系統(tǒng)的復雜處理過程提供方便的調用方法,使得子系統(tǒng)更加容易被使用。 -->將復雜的過程包含在里面,提供一個簡單的應用接口即可. (2)
例如在一個泡茶的過程中,需要作如下的工作:燒開水,準備茶葉,把茶葉放在被子里,把燒開的水放到茶杯中,只 有經過這些過程之后才能泡出好的茶葉來。這是一個常用的步驟,80%的泡茶步驟都是這個樣子的,可以把這些動作串
聯(lián)起來,形成一個整體的步驟.如下例的MakeACuppa(),使用了facade的模式,這樣在調用步方法時就比較方便。這便
是外觀模式,里面的細節(jié)被屏蔽掉了。
public class TeaCup{.....}
public class TeaBag{.....}
public class Water{.....}
public class FacadeCuppaMaker{
private boolean TeaBagIsSteeped; public FacadeCuppaMaker(){ System.out.println("FacadeCuppaMaker 準備好沖茶了"); } public TeaCup makeACuppa(){ TeaCup cup = new TeaCup(); TeaBag teaBag= new TeaBag(); Water water = new Water(); cup.addFacadeTeaBag(teaBag); water.boilFacadeWater(); cup.addFacadeWater(water); cup.steepTeaBag(); return cup; } } ------------------------------ 適配器模式(adapter) -------------------------------
(1) 適配器模式的意圖是將一個已存在的類/接口進行復用,將其轉換/具體化成客戶希望的另外的一個類/接口。 (2) 如何實例復用: 將要進行復用的類,放到目標類的構造方法中,進行實例化,然后在目標類的相應方法中,進行調用,修改原來方法 中的參數,或添加相應的邏輯。即復用了已有類的原來方法。
要被復用的類:
public class Adaptee{ public long getPower(long base,long exp){ long result=1; for(int i=0;i<exp;i++) result*=base; return result; } } 目標類:--也可直接實現,不用接口。
public interface Target{ public long get2Power(long exp); } public class Adapter implements Target{
private Adaptee pt; public Adapter(){ pt = new Adaptee(); } public long get2Power(long exp){ return pt.getPower(2,exp); ---修改原來方法中的參數, } } (3)
又如: 在SCM中添加的方法: 已有接口: public boolean updateRecordStates(Double recordId,Double tableNameMapping,int state,boolean subRecordUpdate) throws RemoteException;
已有實現類: public boolean updateRecordStates(Double recordId,Double tableNameMapping,int state,boolean subRecordUpdate) throws RemoteException
{ return moveTable.updateRecordStates(recordId,tableNameMapping,state,subRecordUpdate); } 若采用適配器模式:
接口: public boolean updateStatesAdapterForSelfPanel(Double recordId,Double tableNameMapping,int state) throws RemoteException;
實現類: public boolean updateStatesAdapterForSelfPanel(Double recordId,Double tableNameMapping,int state) throws RemoteException
{ return this.updateRecordStates(recordId,tableNameMapping,state,false); } ------------------------------ 代理模式(Proxy) -------------------------------
(1) 代理的好處: --->是可以在間接訪問對象的同時,要其前或后,添加其它的邏輯代碼. --->對原來邏輯進行添加其它邏輯,最終生成新的邏輯.即:對類的方法添加一些額外的邏輯,生成新的方法邏輯. (2)
靜態(tài)代理: -->一個原類與一個代理類要一一對應。 -->兩者都實現共同的接口或繼承相同的抽象類; -->只是在代理類中,實例化原類,在原類方法的前后添加新的邏輯。 如下: 抽象角色: abstract public class Subject { abstract public void request(); } 真實角色:
public class RealSubject extends Subject { public void request() { System.out.println("From real subject."); } } 代理角色:
public class ProxySubject extends Subject {
private RealSubject realSubject; //以真實角色作為代理角色的屬性 public ProxySubject()
{ realSubject=new RealSubject(); } public void request() //與原方法名相同
{ preRequest(); realSubject.request(); //此處執(zhí)行真實對象的request方法
postRequest();
} private void preRequest()
{ //something you want to do before requesting } private void postRequest() { //something you want to do after requesting } } 客戶端調用:
Subject sub=new ProxySubject(); Sub.request(); (3)
動態(tài)代理類 Java動態(tài)代理類位于Java.lang.reflect包下,一般主要涉及到以下兩個類: 1) Interface InvocationHandler:該接口中僅定義了一個方法:invoke(Object obj,Method method, Object[] args) 。在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,args為該方法的參數數組。這個抽象方法
在代理類中動態(tài)實現。
2) Proxy:該類即為動態(tài)代理類,其中主要包含以下內容: Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類 的一個實例,返回后的代理類可以當作被代理類使用。
所謂Dynamic Proxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,然后 該class就宣稱它實現了這些 interface。
3) 在使用動態(tài)代理類時,我們必須實現InvocationHandler接口, public interface Subject { public void request(); } 具體角色RealSubject:同上;
代理角色:
import java.lang.reflect.Method; import java.lang.reflect.InvocationHandler; public class DynamicSubject implements InvocationHandler { private Object sub; public DynamicSubject(Object obj) { sub = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling " + method); method.invoke(sub,args);
System.out.println("after calling " + method);
return null; } }
==> method.invoke(sub,args); 其實就是調用被代理對象的將要被執(zhí)行的方法,方法參數sub是實際的被代理對象,args為執(zhí)行被代理對象相應操作所 需的參數。通過動態(tài)代理類,我們可以在調用之前或之后執(zhí)行一些相關操作。
客戶端:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class Client
{ static public void main(String[] args) throws Throwable { RealSubject rs = new RealSubject(); //在這里指定被代理類 InvocationHandler ds = new DynamicSubject(rs); //初始化代理類 Subject subject = (Subject) Proxy.newProxyInstance(rs.getClass().getClassLoader(),rs.getClass ().getInterfaces(),ds );
subject.request(); } 5)
實例二: package dynamicProxy; public interface Work { public void startWork(); } package dynamicProxy;
public class JasonWork implements Work { public void startWork() { System.out.println("jason start to work..."); } } public interface Play {
public void startPlay(); } public class JasonPlay implements Play {
public void startPlay() { System.out.println("jason start to play..."); } } public class Test {
public static void main(String[] args) { JasonWork work=new JasonWork(); InvocationHandler dynamicProxy=new DynamicProxy(work); Work jasonproxy=(Work)Proxy.newProxyInstance(work.getClass().getClassLoader(), work.getClass().getInterfaces(), dynamicProxy);
jasonproxy.startWork(); JasonPlay play=new JasonPlay();
InvocationHandler dynamicProxy=new DynamicProxy(play); Play jasonproxy=(Play)Proxy.newProxyInstance(play.getClass().getClassLoader(), play.getClass().getInterfaces(), dynamicProxy);
jasonproxy.startPlay(); } } ===>動態(tài)代理類,可以與任何類型的真實類(work/play),進行結合,進行動態(tài)的代理. ------------------------------ 狀態(tài)模式(state) -------------------------------
(1) State模式定義: 不同的狀態(tài),不同的行為; 或者說,每個狀態(tài)有著相應的行為. 適用場合: State模式在實際使用中比較多,適合"狀態(tài)的切換".因為我們經常會使用If elseif else 進行狀態(tài)切換, 如果針對狀態(tài)的這樣判斷切換反復出現,我們就要聯(lián)想到是否可以采取State模式了. -->適合于內部狀態(tài),不斷循環(huán)變化的.
(2)
一個state,包括兩部分: 對象 + 對象內部的屬性(屬性接口+具體屬性) 一個對象,要有其屬性,以及其setter,getter.且設置好其初始狀態(tài)+一個調用顯示狀態(tài)的方法(里面就是狀態(tài)調用自身的顯示方法). 一個屬性接口,應該有一個執(zhí)行的方法. 一個具體屬性,須包含對象進去,實現方法中,須設置對象下一個要顯示的屬性-->從而在對象下次調用方法時,其屬性值會變化. 狀態(tài)模式與觀察者模式的區(qū)別:
狀態(tài)模式,也跟觀察者模式一樣,是一對多的模式。但觀察者模式是“一”變了,所有的“多”也會更新。
狀態(tài)模式,強調的是:“多”是“一”的各個狀態(tài),“一”的各個狀態(tài),進行不斷的循環(huán)。
如何建立一與多的關系:
“多”,都是實現一個接口的。所以,在“一”的類中,聲明的是“多”的接口;若“多”中要建立與“一”的關系,只須直接在類中聲明“一”即可。
(3)
代碼: public interface Color { public void show(); }
package state;
class Light
{ Color color; public Color getColor() { return color; } public void setColor(Color color) { this.color = color; } public Light() { color=new RedColor(this); } public void showColor() { color.show(); } } class RedColor implements Color
{ Light light; public RedColor(Light light) { this.light=light; } public void show() { System.out.println("the color is red,the car must stop !"); System.out.println("write down all logic shoud do this in this state....."); light.setColor(new GreenColor(light)); } } class GreenColor implements Color
{ Light light; public GreenColor(Light light) { this.light=light; } public void show() { System.out.println("the color is green,the car can run !"); System.out.println("write down all logic shoud do this in this state....."); light.setColor(new YellowColor(light)); } } class YellowColor implements Color
{ Light light; public YellowColor(Light light) { this.light=light; } public void show() { System.out.println("the color is yellow,the car shoud stop !"); System.out.println("write down all logic shoud do this in this state....."); light.setColor(new RedColor(light)); } } public class CarLight {
public static void main(String[] args) { Light light=new Light(); //初始調用為紅燈 light.showColor(); //再調用為綠燈 light.showColor(); //再調用為黃燈 light.showColor(); //不斷調用,不斷循環(huán). } } ------------------------------ 享元模式(Flyweight) -------------------------------
(1) 主要用于創(chuàng)建對象時,運用共享技術,減少對象對內存的占用.一個提高程序效率和性能的模式,會大大加快程序的運 行速度.
就是說在一個系統(tǒng)中如果有多個相同的對象,那么只共享一份就可以了,不必每個都去實例化一個對象。 Flyweight(享元)模式中常出現Factory模式。Flyweight的內部狀態(tài)是用來共享的,Flyweight factory負責維護一個對
象存儲池(Flyweight Pool)來存放內部狀態(tài)的對象。
Flyweight的關鍵思路,在于:
新建對象時: 先到hashtable中進行獲取-->判斷取得對象是否為空-->若是,則新建此對象,且放回hashtable -->若存在,則共享原來 的對象.
(2)
實例: (與靜態(tài)工廠模式進行對比) public interface Car { public void showCarName(); }
class BMWCar implements Car
{ public void showCarName() { System.out.println("this is the BMWCar ."); } } class FordCar implements Car
{ public void showCarName() { System.out.println("this is the FordCar ."); } } class CarFactory
{ public static Car car; public static Car getCar(String name) { if("BMW".equals(name)) { car = new BMWCar(); } if("Ford".equals(name)) { car = new FordCar(); } return car; } } class CarFlyWeightFactory
{ public Car car; private Hashtable<String,Car> carPool=new Hashtable<String,Car>(); public Car getCar(String name) { if("BMW".equals(name)) { car=carPool.get(name); if(car==null) { car=new BMWCar(); carPool.put(name, car); } } if("Ford".equals(name)) { car=carPool.get(name); if(car==null) { car=new FordCar(); carPool.put(name, car); } } return car; } public int getNumber(){ return carPool.getSize(); } } public class Test { public static void main(String[] args) {
CarFlyWeightFactory carFlyWeightFactory=new CarFlyWeightFactory(); Car carf1=carFlyWeightFactory.getCar("Ford"); carf1.showCarName(); Car carf2=carFlyWeightFactory.getCar("Ford"); carf2.showCarName(); if(carf1==carf2) { System.out.println("同一部車來的"); } else { System.out.println("不同一部車來的"); } System.out.println("車的數量是:"+carFlyWeightFactory.getNumber()); } } 輸出:
this is the FordCar . this is the FordCar . 同一部車來的 ---------------------- 職責鏈模式(Chain of Responsibility) -----------------------
(1) Chain of Responsibility職責鏈模式: 為了避免請求的發(fā)送者和接收者之間的耦合關系,使多個接受對象都有機會處理請求。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。 --> 要沿著鏈轉發(fā)請求,并保證接受者為隱式的,每個鏈上的對象都有一致的處理請求和訪問鏈上后繼者的接口(即如下實例中,在自己方法中再調用一次相同的方法)。 (2)
public class Boy { private boolean hasCar; // 是否有車 private boolean hasHouse; // 是否有房 private boolean hasResponsibility; // 是否有責任心 public Boy() {
} public Boy(boolean hasCar, boolean hasHouse, boolean hasResponsibility) {
this.hasCar = hasCar; this.hasHouse = hasHouse; this.hasResponsibility = hasResponsibility; } public boolean isHasCar() {
return hasCar; } public void setHasCar(boolean hasCar) {
this.hasCar = hasCar; } public boolean isHasHouse() {
return hasHouse; } public void setHasHouse(boolean hasHouse) {
this.hasHouse = hasHouse; } public boolean isHasResponsibility() {
return hasResponsibility; } public void setHasResponsibility(boolean hasResponsibility) {
this.hasResponsibility = hasResponsibility; } } public interface Handler {
public void handleRequest(Boy boy); } public class HouseHandler implements Handler {
private Handler handler; public HouseHandler(Handler handler) {
this.handler = handler;
} public Handler getHandler() {
return handler; } public void setHandler(Handler handler) {
this.handler = handler; } public void handleRequest(Boy boy) {
if (boy.isHasHouse()) { System.out.println("沒想到吧,我還有房子"); } else { System.out.println("我也沒有房"); handler.handleRequest(boy); } } } public class CarHandler implements Handler {
private Handler handler;
public CarHandler(Handler handler) {
this.handler = handler; } public Handler getHandler() {
return handler; } public void setHandler(Handler handler) {
this.handler = handler; } public void handleRequest(Boy boy) {
if (boy.isHasCar()) { System.out.println("呵呵,我有輛車"); } else { System.out.println("我沒有車"); handler.handleRequest(boy); } } } public class ResponsibilityHandler implements Handler {
private Handler handler;
public ResponsibilityHandler(Handler handler) {
this.handler = handler; } public Handler getHandler() {
return handler; } public void setHandler(Handler handler) {
this.handler = handler; } public void handleRequest(Boy boy) {
if (boy.isHasResponsibility()) { System.out.println("我只有一顆帶Responsibility的心"); } else { System.out.println("更沒有責任心"); handler.handleRequest(boy); } } } public class Girl {
public static void main(String[] args) { // 這個boy沒有車,也沒有房,不過很有責任心 Boy boy = new Boy(false, false, true); // 也可以使用setHanlder方法 Handler handler = new CarHandler(new HouseHandler( new ResponsibilityHandler(null))); handler.handleRequest(boy); } } ==>
如何實例使請求沿著鏈在各接受對象中傳遞,當沒被第一個接受對象接受時,會傳遞給第二個對象,若被第一個對象接受了,則不傳遞下去: 1.各具體的接受對象采用這樣的構造方法: public CarHandler(Handler handler) { this.handler = handler; } 2.各具體的接受對象實現接口的方法handleRequest()中.在調用時,若被接受,則執(zhí)行true的內容,若不被接受,則執(zhí)行false的內容,并繼續(xù)調用再調用handleRequest()方法. 3.在最后的測試類中,生成具體的handler時,用多層包含的形式.這樣,在調用了上一層car的方法后,會調用house的相應方法,最后再調用ResponsibilityHandler的方法. ==>前兩個handler是采用了有參數的構造方法,最后一個是采用了為NULL的構造方法
------------------------------ 備忘錄模式(Memento) ------------------------------- (1) 備忘錄模式屬于行為型模式,其意圖是在不破壞封裝性的前提下,捕獲一個對象的內部狀態(tài),并在該對象之外保存這 個狀態(tài),這樣以后就可以將對象恢復到原先保存的狀態(tài)。
(2)
實例如下: 有一個對象Employee.除了屬性外,還需要一個保存,還原狀態(tài)的方法. 有一個對象Memento,用來記錄Employee每一個時刻的狀態(tài), CareTaker,用來保存,拿回Memento.需要一個保存,還原狀態(tài)的方法.->需要一個指針,一個容器. package memento;
public class Memento{ String name; int age; public Memento(String name,int age){ this.name = name; this.age = age; } } Employee模式: package memento; public class Employee{ private String name; private int age; public Employee(String aName,int aAge){ name = aName; age = aAge; } public void setName(String aName){ name = aName; } public void setAge(int aAge){ age = aAge; } public Memento saveMemento(){ return new Memento(name,age); } public void restoreMemento(Memento memento){ age = memento.age; name = memento.name; } public int getAge(){ return age; } public String getName(){ return name; } } CareTaker代碼: package memento; import java.util.Vector; public class CareTaker{ private Vector v; private int current; public CareTaker(){ current = -1; v = new Vector(); } public void setMemento(Memento mem){ current ++; v.add(mem); } public Memento getMemento(){ if(current>0){ current --; return(Memento) v.get(current); } return null; } } Client代碼: package memento; public class Client{ public static void show(Employee e){ System.out.println("-----------------------------------"); System.out.println("Name:"+e.getName()); System.out.println("Age:" + e.getAge()); System.out.println("-----------------------------------"); } public static void main(String[] args){ Employee e = new Employee("lili",25); CareTaker ct = new CareTaker(); show(e); ct.setMemento(e.saveMemento()); e.setName("litianli"); show(e); ct.setMemento(e.saveMemento()); e.setAge(45); show(e); ct.setMemento(e.saveMemento()); //restore e.restoreMemento(ct.getMemento()); show(e); e.restoreMemento(ct.getMemento()); show(e); } } 本文出自 “Changes we need ! ” 博客,請務必保留此出處http://shenzhenchufa.blog.51cto.com/730213/161581 |
|
來自: 昵稱14566950 > 《IT》