java中經常使用的設計模式
阿新 • • 發佈:2019-02-10
設計模式;
一個程式設計師對設計模式的理解:
“不懂”為什麼要把很簡單的東西搞得那麼複雜。後來隨著軟體開發經驗的增加才開始明白我所看到的“複雜”恰恰就是設計模式的精髓所在,我所理解的“簡單”就是一把鑰匙開一把鎖的模式,目的僅僅是著眼於解決現在的問題,而設計模式的“複雜”就在於它是要構造一個“萬能鑰匙”,目的是提出一種對所有鎖的開鎖方案。在真正理解設計模式之前我一直在編寫“簡單”的程式碼.
這個“簡單”不是功能的簡單,而是設計的簡單。簡單的設計意味著缺少靈活性,程式碼很鋼硬,只在這個專案裡有用,拿到其它的專案中就是垃圾,我將其稱之為“一次性程式碼”。 -->要使程式碼可被反覆使用,請用'設計模式'對你的程式碼進行設計. 很多我所認識的程式設計師在接觸到設計模式之後,都有一種相見恨晚的感覺,有人形容學習了設計模式之後感覺自己好像已經脫胎換骨,達到了新的境界,還有人甚至把是否瞭解設計模式作為程式設計師劃分水平的標準。
我們也不能陷入模式的陷阱,為了使用模式而去套模式,那樣會陷入形式主義。我們在使用模式的時候,一定要注意模式的意圖(intent),而不 要過多的去關注模式的實現細節,因為這些實現細節在特定情況下,可能會發生一些改變。不要頑固地認為設計模式一書中的類圖或實現程式碼就代表了模式本身。
設計原則:(重要)
1.
邏輯程式碼獨立到單獨的方法中,注重封裝性--易讀,易複用。
不要在一個方法中,寫下上百行的邏輯程式碼。把各小邏輯程式碼獨立出來,寫於其它方法中,易讀其可重複呼叫。
2.
寫類,寫方法,寫功能時,應考慮其移植性,複用性:防止一次性程式碼!
是否可以拿到其它同類事物中應該?是否可以拿到其它系統中應該?
3.
熟練運用繼承的思想:
找出應用中相同之處,且不容易發生變化的東西,把它們抽取到抽象類中,讓子類去繼承它們;
繼承的思想,也方便將自己的邏輯建立於別人的成果之上。如ImageField extends JTextField;
熟練運用介面的思想:
找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。
把很簡單的東西搞得那麼複雜,一次性程式碼,設計模式優勢的例項說明:(策略模式)
說明:
模擬鴨子游戲的應用程式,要求:遊戲中會出現各種顏色外形的鴨子,一邊游泳戲水,一邊呱呱叫。 第一種方法:(一次性程式碼)
直接編寫出各種鴨子的類: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了。但是問題又出來了,客戶又提出有的鴨子會飛,有的不能飛。 >>>>>>點評:
對於上面的設計,你可能發現一些弊端,如果超類有新的特性,子類都必須變動,這是我們開發最不喜歡看到的,一個類變讓另一個類也跟著變,這有點不符合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(策略模式) -------------------------
我們有一個設計原則:
找出應用中相同之處,且不容易發生變化的東西,把它們抽取到抽象類中,讓子類去繼承它們;
找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。 -->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 的例項化寫在子類了。我們還可以動態的來決定。
我們只需在Duck中加上兩個方法。 在構造方法中對屬性進行賦值與用屬性的setter的區別: 構造方法中對屬性進行賦值:固定,不可變; 用屬性的setter,可以在例項化物件後,動態的變化,比較靈活。
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(靜態工廠) -------------------------
(1)
在設計模式中,Factory Method也是比較簡單的一個,但應用非常廣泛,EJB,RMI,COM,CORBA,Swing中都可以看到此模式 的影子,它是最重要的模式之一.在很多地方我們都會看到xxxFactory這樣命名的類. (2)
基本概念:
FactoryMethod是一種建立性模式,它定義了一個建立物件的介面,但是卻讓子類來決定具體例項化哪一個類.
通常我們將Factory Method作為一種標準的建立物件的方法。 應用方面:
當一個類無法預料要建立哪種類的物件或是一個類需要由子類來指定建立的物件時我們就需要用到Factory Method 模 式了. -------------------------------- singelton(單例模式) --------------------------------
基本概念:
Singleton 是一種建立性模型,它用來確保只產生一個例項,並提供一個訪問它的全域性訪問點.對一些類來說,保證只有一個例項是很重要的,比如有的時候,資料庫連線或 Socket 連線要受到一定的限制,必須保持同一時間只能有一個連線的存在. 運用:
在於使用static變數;
建立類物件,一般是在構造方法中,或用一個方法來建立類物件。在這裡方法中,加對相應的判斷即可。 單態模式與共享模式的區別: 單態模式與共享模式都是讓類的例項是唯一的。 但單態模式的實現方式是: 在類的內部.即在構造方法中,或靜態的getInstace方法中,進行判斷,若例項存在,則直接返回,不進行建立; 共享模式的實現方式是: 每次要用到此例項時,先去此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)
基本概念:
觀察者模式屬於行為型模式,其意圖是定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。 這一個模式的關鍵物件是目標(Subject)和觀察者(Observer)。一個目標可以有任意數目的依賴它的觀察者,一旦目標的狀態發生改變,所有的觀察者都得到通知,作為對這個通知的響應,每個觀察者都將查詢目標以使其狀態與目標的狀態同步。 適用場景: 觀察者模式,用於存在一對多依賴關係的物件間,當被依賴者變化時,通知依賴者全部進行更新。因此,被依賴者,應該有新增/刪除依賴者的方法,且可以將新增的依賴者放到一個容器中;且有一個方法去通知依賴者進行更新。 (2)
思想:
(一)
建立目標(subject)與觀察者(observer)介面:
目標(subject)介面:
建立一個註冊觀察者物件的介面; public void attach(Observer o);
建立一個刪除觀察者物件的介面; public void detach(Observer o);
建立一個當目標狀態發生改變時,釋出通知給觀察者物件的介面; public void notice(); 觀察者(observer)介面:
建立一個當收到目標通知後的更新介面: public void update(); (3)
例項:
老師又電話號碼,學生需要知道老師的電話號碼以便於在合時的時候撥打,在這樣的組合中,老師就是一個被觀察者 (Subject),學生就是需要知道資訊的觀察者,當老師的電話號碼發生改變時,學生得到通知,並更新相應的電話記 錄。 具體例項如下:
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模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
外觀模式的主要用途就是為子系統的複雜處理過程提供方便的呼叫方法,使得子系統更加容易被使用。
-->將複雜的過程包含在裡面,提供一個簡單的應用介面即可. (2)
例如在一個泡茶的過程中,需要作如下的工作:燒開水,準備茶葉,把茶葉放在被子裡,把燒開的水放到茶杯中,只 有經過這些過程之後才能泡出好的茶葉來。這是一個常用的步驟,80%的泡茶步驟都是這個樣子的,可以把這些動作串 聯起來,形成一個整體的步驟.如下例的MakeACuppa(),使用了facade的模式,這樣在呼叫步方法時就比較方便。這便 是外觀模式,裡面的細節被遮蔽掉了。 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)
靜態代理:
-->一個原類與一個代理類要一一對應。
-->兩者都實現共同的介面或繼承相同的抽象類;
-->只是在代理類中,例項化原類,在原類方法的前後新增新的邏輯。
如下:
抽象角色:
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(); //此處執行真實物件的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)
動態代理類
Java動態代理類位於Java.lang.reflect包下,一般主要涉及到以下兩個類:
1)
Interface InvocationHandler:該介面中僅定義了一個方法:invoke(Object obj,Method method, Object[] args) 。在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,args為該方法的引數陣列。這個抽象方法 在代理類中動態實現。
2)
Proxy:該類即為動態代理類,其中主要包含以下內容:
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類 的一個例項,返回後的代理類可以當作被代理類使用。
所謂Dynamic Proxy是這樣一種class:它是在執行時生成的class,在生成它時你必須提供一組interface給它,然後 該class就宣稱它實現了這些 interface。
3)
在使用動態代理類時,我們必須實現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);
其實就是呼叫被代理物件的將要被執行的方法,方法引數sub是實際的被代理物件,args為執行被代理物件相應操作所 需的引數。通過動態代理類,我們可以在呼叫之前或之後執行一些相關操作。 客戶端:
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();
}
}
===>動態代理類,可以與任何型別的真實類(work/play),進行結合,進行動態的代理. ------------------------------ 狀態模式(state) -------------------------------
(1)
State模式定義:
不同的狀態,不同的行為; 或者說,每個狀態有著相應的行為.
適用場合:
State模式在實際使用中比較多,適合"狀態的切換".因為我們經常會使用If elseif else 進行狀態切換, 如果針對狀態的這樣判斷切換反覆出現,我們就要聯想到是否可以採取State模式了. -->適合於內部狀態,不斷迴圈變化的. (2)
一個state,包括兩部分: 物件 + 物件內部的屬性(屬性介面+具體屬性)
一個物件,要有其屬性,以及其setter,getter.且設定好其初始狀態+一個呼叫顯示狀態的方法(裡面就是狀態呼叫自身的顯示方法).
一個屬性介面,應該有一個執行的方法.
一個具體屬性,須包含物件進去,實現方法中,須設定物件下一個要顯示的屬性-->從而在物件下次呼叫方法時,其屬性值會變化. 狀態模式與觀察者模式的區別: 狀態模式,也跟觀察者模式一樣,是一對多的模式。但觀察者模式是“一”變了,所有的“多”也會更新。 狀態模式,強調的是:“多”是“一”的各個狀態,“一”的各個狀態,進行不斷的迴圈。 如何建立一與多的關係: “多”,都是實現一個介面的。所以,在“一”的類中,宣告的是“多”的介面;若“多”中要建立與“一”的關係,只須直接在類中宣告“一”即可。 (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();
//不斷呼叫,不斷迴圈.
}
} ------------------------------ 享元模式(Flyweight) -------------------------------
(1)
主要用於建立物件時,運用共享技術,減少物件對記憶體的佔用.一個提高程式效率和效能的模式,會大大加快程式的運 行速度.
就是說在一個系統中如果有多個相同的物件,那麼只共享一份就可以了,不必每個都去例項化一個物件。 Flyweight(享元)模式中常出現Factory模式。Flyweight的內部狀態是用來共享的,Flyweight factory負責維護一個對 象儲存池(Flyweight Pool)來存放內部狀態的物件。 Flyweight的關鍵思路,在於:
新建物件時:
先到hashtable中進行獲取-->判斷取得物件是否為空-->若是,則新建此物件,且放回hashtable -->若存在,則共享原來 的物件. (2)
例項: (與靜態工廠模式進行對比)
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職責鏈模式:
為了避免請求的傳送者和接收者之間的耦合關係,使多個接受物件都有機會處理請求。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為止。
-->
要沿著鏈轉發請求,並保證接受者為隱式的,每個鏈上的物件都有一致的處理請求和訪問鏈上後繼者的介面(即如下例項中,在自己方法中再呼叫一次相同的方法)。 (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
一個程式設計師對設計模式的理解:
“不懂”為什麼要把很簡單的東西搞得那麼複雜。後來隨著軟體開發經驗的增加才開始明白我所看到的“複雜”恰恰就是設計模式的精髓所在,我所理解的“簡單”就是一把鑰匙開一把鎖的模式,目的僅僅是著眼於解決現在的問題,而設計模式的“複雜”就在於它是要構造一個“萬能鑰匙”,目的是提出一種對所有鎖的開鎖方案。在真正理解設計模式之前我一直在編寫“簡單”的程式碼.
這個“簡單”不是功能的簡單,而是設計的簡單。簡單的設計意味著缺少靈活性,程式碼很鋼硬,只在這個專案裡有用,拿到其它的專案中就是垃圾,我將其稱之為“一次性程式碼”。 -->要使程式碼可被反覆使用,請用'設計模式'對你的程式碼進行設計. 很多我所認識的程式設計師在接觸到設計模式之後,都有一種相見恨晚的感覺,有人形容學習了設計模式之後感覺自己好像已經脫胎換骨,達到了新的境界,還有人甚至把是否瞭解設計模式作為程式設計師劃分水平的標準。
設計原則:(重要)
1.
邏輯程式碼獨立到單獨的方法中,注重封裝性--易讀,易複用。
不要在一個方法中,寫下上百行的邏輯程式碼。把各小邏輯程式碼獨立出來,寫於其它方法中,易讀其可重複呼叫。
2.
寫類,寫方法,寫功能時,應考慮其移植性,複用性:防止一次性程式碼!
是否可以拿到其它同類事物中應該?是否可以拿到其它系統中應該?
3.
熟練運用繼承的思想:
找出應用中相同之處,且不容易發生變化的東西,把它們抽取到抽象類中,讓子類去繼承它們;
繼承的思想,也方便將自己的邏輯建立於別人的成果之上。如ImageField extends JTextField;
熟練運用介面的思想:
找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。
把很簡單的東西搞得那麼複雜,一次性程式碼,設計模式優勢的例項說明:(策略模式)
說明:
模擬鴨子游戲的應用程式,要求:遊戲中會出現各種顏色外形的鴨子,一邊游泳戲水,一邊呱呱叫。 第一種方法:(一次性程式碼)
直接編寫出各種鴨子的類: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了。但是問題又出來了,客戶又提出有的鴨子會飛,有的不能飛。 >>>>>>點評:
對於上面的設計,你可能發現一些弊端,如果超類有新的特性,子類都必須變動,這是我們開發最不喜歡看到的,一個類變讓另一個類也跟著變,這有點不符合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(策略模式) -------------------------
我們有一個設計原則:
找出應用中相同之處,且不容易發生變化的東西,把它們抽取到抽象類中,讓子類去繼承它們;
找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的程式碼混在一起。 -->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 的例項化寫在子類了。我們還可以動態的來決定。
我們只需在Duck中加上兩個方法。 在構造方法中對屬性進行賦值與用屬性的setter的區別: 構造方法中對屬性進行賦值:固定,不可變; 用屬性的setter,可以在例項化物件後,動態的變化,比較靈活。
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(靜態工廠) -------------------------
(1)
在設計模式中,Factory Method也是比較簡單的一個,但應用非常廣泛,EJB,RMI,COM,CORBA,Swing中都可以看到此模式 的影子,它是最重要的模式之一.在很多地方我們都會看到xxxFactory這樣命名的類. (2)
基本概念:
FactoryMethod是一種建立性模式,它定義了一個建立物件的介面,但是卻讓子類來決定具體例項化哪一個類.
通常我們將Factory Method作為一種標準的建立物件的方法。 應用方面:
當一個類無法預料要建立哪種類的物件或是一個類需要由子類來指定建立的物件時我們就需要用到Factory Method 模 式了. -------------------------------- singelton(單例模式) --------------------------------
基本概念:
Singleton 是一種建立性模型,它用來確保只產生一個例項,並提供一個訪問它的全域性訪問點.對一些類來說,保證只有一個例項是很重要的,比如有的時候,資料庫連線或 Socket 連線要受到一定的限制,必須保持同一時間只能有一個連線的存在. 運用:
在於使用static變數;
建立類物件,一般是在構造方法中,或用一個方法來建立類物件。在這裡方法中,加對相應的判斷即可。 單態模式與共享模式的區別: 單態模式與共享模式都是讓類的例項是唯一的。 但單態模式的實現方式是: 在類的內部.即在構造方法中,或靜態的getInstace方法中,進行判斷,若例項存在,則直接返回,不進行建立; 共享模式的實現方式是: 每次要用到此例項時,先去此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)
基本概念:
觀察者模式屬於行為型模式,其意圖是定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。 這一個模式的關鍵物件是目標(Subject)和觀察者(Observer)。一個目標可以有任意數目的依賴它的觀察者,一旦目標的狀態發生改變,所有的觀察者都得到通知,作為對這個通知的響應,每個觀察者都將查詢目標以使其狀態與目標的狀態同步。 適用場景: 觀察者模式,用於存在一對多依賴關係的物件間,當被依賴者變化時,通知依賴者全部進行更新。因此,被依賴者,應該有新增/刪除依賴者的方法,且可以將新增的依賴者放到一個容器中;且有一個方法去通知依賴者進行更新。 (2)
思想:
(一)
建立目標(subject)與觀察者(observer)介面:
目標(subject)介面:
建立一個註冊觀察者物件的介面; public void attach(Observer o);
建立一個刪除觀察者物件的介面; public void detach(Observer o);
建立一個當目標狀態發生改變時,釋出通知給觀察者物件的介面; public void notice(); 觀察者(observer)介面:
建立一個當收到目標通知後的更新介面: public void update(); (3)
例項:
老師又電話號碼,學生需要知道老師的電話號碼以便於在合時的時候撥打,在這樣的組合中,老師就是一個被觀察者 (Subject),學生就是需要知道資訊的觀察者,當老師的電話號碼發生改變時,學生得到通知,並更新相應的電話記 錄。 具體例項如下:
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模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
外觀模式的主要用途就是為子系統的複雜處理過程提供方便的呼叫方法,使得子系統更加容易被使用。
-->將複雜的過程包含在裡面,提供一個簡單的應用介面即可. (2)
例如在一個泡茶的過程中,需要作如下的工作:燒開水,準備茶葉,把茶葉放在被子裡,把燒開的水放到茶杯中,只 有經過這些過程之後才能泡出好的茶葉來。這是一個常用的步驟,80%的泡茶步驟都是這個樣子的,可以把這些動作串 聯起來,形成一個整體的步驟.如下例的MakeACuppa(),使用了facade的模式,這樣在呼叫步方法時就比較方便。這便 是外觀模式,裡面的細節被遮蔽掉了。 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)
靜態代理:
-->一個原類與一個代理類要一一對應。
-->兩者都實現共同的介面或繼承相同的抽象類;
-->只是在代理類中,例項化原類,在原類方法的前後新增新的邏輯。
如下:
抽象角色:
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(); //此處執行真實物件的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)
動態代理類
Java動態代理類位於Java.lang.reflect包下,一般主要涉及到以下兩個類:
1)
Interface InvocationHandler:該介面中僅定義了一個方法:invoke(Object obj,Method method, Object[] args) 。在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,args為該方法的引數陣列。這個抽象方法 在代理類中動態實現。
2)
Proxy:該類即為動態代理類,其中主要包含以下內容:
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類 的一個例項,返回後的代理類可以當作被代理類使用。
所謂Dynamic Proxy是這樣一種class:它是在執行時生成的class,在生成它時你必須提供一組interface給它,然後 該class就宣稱它實現了這些 interface。
3)
在使用動態代理類時,我們必須實現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);
其實就是呼叫被代理物件的將要被執行的方法,方法引數sub是實際的被代理物件,args為執行被代理物件相應操作所 需的引數。通過動態代理類,我們可以在呼叫之前或之後執行一些相關操作。 客戶端:
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();
}
}
===>動態代理類,可以與任何型別的真實類(work/play),進行結合,進行動態的代理. ------------------------------ 狀態模式(state) -------------------------------
(1)
State模式定義:
不同的狀態,不同的行為; 或者說,每個狀態有著相應的行為.
適用場合:
State模式在實際使用中比較多,適合"狀態的切換".因為我們經常會使用If elseif else 進行狀態切換, 如果針對狀態的這樣判斷切換反覆出現,我們就要聯想到是否可以採取State模式了. -->適合於內部狀態,不斷迴圈變化的. (2)
一個state,包括兩部分: 物件 + 物件內部的屬性(屬性介面+具體屬性)
一個物件,要有其屬性,以及其setter,getter.且設定好其初始狀態+一個呼叫顯示狀態的方法(裡面就是狀態呼叫自身的顯示方法).
一個屬性介面,應該有一個執行的方法.
一個具體屬性,須包含物件進去,實現方法中,須設定物件下一個要顯示的屬性-->從而在物件下次呼叫方法時,其屬性值會變化. 狀態模式與觀察者模式的區別: 狀態模式,也跟觀察者模式一樣,是一對多的模式。但觀察者模式是“一”變了,所有的“多”也會更新。 狀態模式,強調的是:“多”是“一”的各個狀態,“一”的各個狀態,進行不斷的迴圈。 如何建立一與多的關係: “多”,都是實現一個介面的。所以,在“一”的類中,宣告的是“多”的介面;若“多”中要建立與“一”的關係,只須直接在類中宣告“一”即可。 (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();
//不斷呼叫,不斷迴圈.
}
} ------------------------------ 享元模式(Flyweight) -------------------------------
(1)
主要用於建立物件時,運用共享技術,減少物件對記憶體的佔用.一個提高程式效率和效能的模式,會大大加快程式的運 行速度.
就是說在一個系統中如果有多個相同的物件,那麼只共享一份就可以了,不必每個都去例項化一個物件。 Flyweight(享元)模式中常出現Factory模式。Flyweight的內部狀態是用來共享的,Flyweight factory負責維護一個對 象儲存池(Flyweight Pool)來存放內部狀態的物件。 Flyweight的關鍵思路,在於:
新建物件時:
先到hashtable中進行獲取-->判斷取得物件是否為空-->若是,則新建此物件,且放回hashtable -->若存在,則共享原來 的物件. (2)
例項: (與靜態工廠模式進行對比)
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職責鏈模式:
為了避免請求的傳送者和接收者之間的耦合關係,使多個接受物件都有機會處理請求。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為止。
-->
要沿著鏈轉發請求,並保證接受者為隱式的,每個鏈上的物件都有一致的處理請求和訪問鏈上後繼者的介面(即如下例項中,在自己方法中再呼叫一次相同的方法)。 (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