Java 設計模式(三)結構型模式

  本系列文章共分爲五篇:
    設計模式的分類與原則
    創建型模式
    結構型模式
    行爲型模式
    設計模式的區別
  上篇文件介紹了創建型模式,本篇將介紹結構型模式。結構型模式的主要關注點是“如何將類或對象按某種佈局組成更大的結構”。

一、適配器模式

1.1 適配器模式定義

  將一個類的接口轉換成客戶希望的另外一個接口,使得原本由於接口不兼容而不能一起工作的那些類能一起工作。適配器模式分爲類結構型模式對象結構型模式兩種,前者之間的耦合度比後者高,且要求開發者瞭解現有組件庫中的相關組件的內部結構,所以應用相對較少些。

1.2 適配器模式特點

  優點:
   1>客戶端通過適配器可以透明地調用目標接口。
   2>複用了現存的類,程序員不需要修改原有代碼而重用現有的適配者類。
   3>將目標類和適配者類解耦,解決了目標類和適配者類接口不一致的問題。
  缺點:
   1>過多地使用適配器,會讓系統非常零亂,不易整體進行把握。

1.3 適配器模式主要角色

  目標接口:當前所期待業務功能實現的接口,它可以是抽象類或接口。
  適配者類:它是現存組件庫中的組件接口
  適配器類:它是一個轉換器,通過繼承或引用適配者的對象,把適配者接口轉換成目標接口,讓客戶按目標接口的格式訪問適配者。

1.4 適配器模式實現方式

  適配器模式的實現方式較多,主要方式如下:

1.4.1 類適配器模式

  該模式是通過類的繼承來實現適配器功能,是較爲簡單的一種適配器模式。以要充電轉接口爲例,某個電子產品的原始充電器是2口的,但電源是3口的,此時就需要一個3口轉2口的適配器。以代碼示例如下:

/*目標接口,使用二口數據線充電*/
public interface TwoSocket {
	public void charge();
}
/*適配者接口,在三口電源座上充電*/
public class ThreeSocket {
    public void powerOn()
    {       
        System.out.println("在三口電源座上充電");
    }
}
/*適配器類,充當轉接口*/
public class SocketAdapter extends ThreeSocket implements TwoSocket{
	public void charge() {
		System.out.println("使用二口電源線連接電子產品,然後用二口電源線連接三口轉兩口適配器");
		powerOn();		
	}
}
/*測試類*/
public class AdapterTest {
    public static void main(String[] args){
    	TwoSocket twoSocket = new SocketAdapter();
    	twoSocket.charge();
    }
}
1.4.2 對象適配器模式

  對象適配器目標接口和適配者接口與類適配器模式中的相同,不同的是適配器類和測試類。在適配器類中,不再繼承適配者接口,而是從調用方傳一個適配者接口對象的參數,其差異代碼示例如下:

/*適配器類,充當轉接口*/
public class SocketAdapter implements TwoSocket{
    private ThreeSocket threeSocket;
    public SocketAdapter(ThreeSocket threeSocket)
    {
        this.threeSocket=threeSocket;
    }
    public void charge()
    {
    	System.out.println("使用二口電源線連接電子產品,然後用二口電源線連接三口轉兩口適配器");
    	threeSocket.powerOn();
    }
}
/*測試類*/
public class AdapterTest {
    public static void main(String[] args){
    	ThreeSocket threeSocket = new ThreeSocket();
    	TwoSocket target = new SocketAdapter(threeSocket);
        target.charge();
    }
}

  兩種適配器模式的輸出結果是一樣的,如下:

使用二口電源線連接電子產品,然後用二口電源線連接三口轉兩口適配器
在三口電源座上充電

1.5 適配器模式應用場景

  適配器模式通常適用的場景:
   1)以前開發的系統存在滿足新系統功能需求的類,但其接口同新系統的接口不一致。
   2)使用第三方提供的組件,但組件接口定義和自己要求的接口定義不同。

二、橋接模式

2.1 橋接模式定義

  將抽象與實現分離,使它們可以獨立變化。它是用組合關係代替繼承關係來實現,從而降低了抽象和實現這兩個可變維度的耦合度。

2.2 橋接模式特點

  優點:
   1>由於抽象與實現分離,所以擴展能力強;
   2>其實現細節對客戶透明。
  缺點:
   1>聚合關係建立在抽象層,要求開發者針對抽象化進行設計與編程,增加了系統的理解與設計難度。

2.3 橋接模式主要角色

  抽象化角色:定義抽象類,幷包含一個對實現化對象的引用。
  擴展抽象化角色:是抽象化角色的子類,實現父類中的業務方法,並通過組合關係調用實現化角色中的業務方法。
  實現化角色:定義實現化角色的接口,供擴展抽象化角色調用。
  具體實現化角色:給出實現化角色接口的具體實現。

2.4 橋接模式實現方式

  橋接模式的意義在於將系統中不同維度的功能分開來實現,降低耦合性,示例代碼如下:

/*實現化角色:顏色*/
public interface Color
{
    String getColor();
}
/*具體實現化角色:綠色*/
class Green implements Color
{
    public String getColor()
    {
        return "green";
    }
}
/*具體實現化角色:紅色*/
public class Red implements Color{
    public String getColor()
    {
        return "red";
    }
}
/*抽象化角色:包*/
public abstract class Bag
{
    protected Color color;
    public void setColor(Color color)
    {
        this.color=color;
    }   
    public abstract String getName();
}
/*擴展抽象化角色:雙肩包*/
public class Knapsack extends Bag
{
    public String getName()
    {
        return color.getColor()+" Knapsack";
    }   
}
/*擴展抽象化角色:錢包*/
public class Wallet extends Bag
{
    public String getName()
    {
        return color.getColor()+" Wallet";
    }   
}
/*測試類*/
public class BridgeTest {
    public static void main(String[] args){
    	Color color = new Red();
        Bag bag=new Knapsack();
        bag.setColor(color);
        System.out.println(bag.getName());
        
    	color = new Green();
        bag=new Knapsack();
        bag.setColor(color);
        System.out.println(bag.getName());
        
    	color = new Red();
        bag=new Wallet();
        bag.setColor(color);
        System.out.println(bag.getName());
     
    	color = new Green();
        bag=new Wallet();
        bag.setColor(color);
        System.out.println(bag.getName());        
    }
}

  結果示例如下:

red Knapsack
green Knapsack
red Wallet
green Wallet

2.5 橋接模式應用場景

  適配器模式通常適用的場景:
   1)當一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展時。
   2)當一個系統不希望使用繼承或因爲多層次繼承導致系統類的個數急劇增加時。
   3)當一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性時。

三、組合模式

3.1 組合模式定義

  又叫作部分-整體模式,它是一種將對象組合成樹狀的層次結構的模式,用來表示“部分-整體”的關係,使用戶對單個對象和組合對象具有一致的訪問性。

3.2 組合模式特點

  優點:
   1>組合模式使得客戶端代碼可以一致地處理單個對象和組合對象,無須關心自己處理的是單個對象,還是組合對象,這簡化了客戶端代碼;
   2>更容易在組合體內加入新的對象,客戶端不會因爲加入了新的對象而更改源代碼,滿足“開閉原則”。
  缺點:
   1>設計較複雜,客戶端需要花更多時間理清類之間的層次關係;
   2>不容易限制容器中的構件;
   3>不容易用繼承的方法來增加構件的新功能。

3.3 組合模式主要角色

  抽象構件角色:它的主要作用是爲樹葉構件和樹枝構件聲明公共接口,並實現它們的默認行爲。在透明式的組合模式中抽象構件還聲明訪問和管理子類的接口;在安全式的組合模式中不聲明訪問和管理子類的接口,管理工作由樹枝構件完成
  樹葉構件角色:是組合中的葉節點對象,它沒有子節點,用於實現抽象構件角色中 聲明的公共接口。
  樹枝構件角色:是組合中的分支節點對象,它有子節點。它實現了抽象構件角色中聲明的接口,它的主要作用是存儲和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

3.4 組合模式實現方式

  組合模式分爲透明式的組合模式和安全式的組合模式。

3.4.1 透明方式

    在該方式中,由於抽象構件聲明瞭所有子類中的全部方法,所以客戶端無須區別樹葉對象和樹枝對象,對客戶端來說是透明的。但其缺點是:樹葉構件本來沒有 Add()、Remove() 及 GetChild() 方法,卻要實現它們(空實現或拋異常)。
    以檢查班級裏有多少人爲例,老師爲樹枝節點,學生爲葉子節點,老師可以在自己的班級中添加、刪減學生。該例子代碼如下:

/*抽象接口*/
public interface  ClassPeople {
    public void add(ClassPeople sp);
    public void remove(ClassPeople sp);
    public ClassPeople getChild(int i);
    public void check();
}
/*老師*/
public class Teacher implements ClassPeople {
    private ArrayList<ClassPeople> children=new ArrayList<ClassPeople>(); 
    private String name;
    public Teacher(String name)
    {
        this.name=name;
    }
	public void add(ClassPeople sp) {
		children.add(sp);
	}
	public void remove(ClassPeople sp) {
		children.remove(sp);
	}
	public ClassPeople getChild(int i) {
		return children.get(i);
	}
	public void check() {
		System.out.println(name+" Teacher");
        for(Object obj:children)
        {
            ((ClassPeople)obj).check();
        }
	}
}
/*學生*/
public class Student implements ClassPeople {
    private String name;
    public Student(String name)
    {
        this.name=name;
    }
	public void add(ClassPeople sp) {
	}

	public void remove(ClassPeople sp) {
	}

	public ClassPeople getChild(int i) {
		return null;
	}

	public void check() {
		System.out.println(name+" Student");
	}
}
/*測試類*/
public class ComponentTest {
    public static void main(String[] args) { 
       ClassPeople sp1 = new Teacher("Jack");
       ClassPeople sp2 = new Student("Marry");
       ClassPeople sp3 = new Student("John");
	   sp1.add(sp2);
	   sp1.add(sp3);
	   sp1.check();
    }
}
3.4.2 安全方式

    在該方式中,將管理子構件的方法移到樹枝構件中,抽象構件和樹葉構件沒有對子對象的管理方法,這樣就避免了上一種方式的安全性問題,但由於葉子和分支有不同的接口,客戶端在調用時要知道樹葉對象和樹枝對象的存在,所以失去了透明性。
    仍以上面的老師學生爲例子,抽象接口中不再具有add、remove、getChild方法,而是在Teacher類中實現,具體代碼如下:

/*抽象接口*/
public interface  ClassPeople {
    public void check();
}
/*老師*/
public class Teacher implements ClassPeople {
    private ArrayList<ClassPeople> children=new ArrayList<ClassPeople>(); 
    private String name;
    public Teacher(String name)
    {
        this.name=name;
    }
	public void add(ClassPeople sp) {
		children.add(sp);
	}
	public void remove(ClassPeople sp) {
		children.remove(sp);
	}
	public ClassPeople getChild(int i) {
		return children.get(i);
	}
	public void check() {
		System.out.println(name+" Teacher");
        for(Object obj:children)
        {
            ((ClassPeople)obj).check();
        }
	}
}
/*學生*/
public class Student implements ClassPeople {
    private String name;
    public Student(String name)
    {
        this.name=name;
    }
	public void check() {
		System.out.println(name+" Student");
	}
}
/*測試類*/
public class ComponentTest {
    public static void main(String[] args) { 
       Teacher sp1 = new Teacher("Jack");
       ClassPeople sp2 = new Student("Marry");
       ClassPeople sp3 = new Student("John");
	   sp1.add(sp2);
	   sp1.add(sp3);
	   sp1.check();
    }
}

  以上兩種方式輸出結果相同,如下:

Jack Teacher
Marry Student
John Student

3.5 組合模式應用場景

  組合模式通常適用的場景:
   1)在需要表示一個對象整體與部分的層次結構的場合。
   2)要求對用戶隱藏組合對象與單個對象的不同,用戶可以用統一的接口使用組合結構中的所有對象的場合。

四、裝飾器模式

4.1 裝飾器模式定義

  在不改變現有對象結構的情況下,動態地給該對象增加一些職責(即增加其額外功能)的模式。

4.2 裝飾器模式特點

  優點:
   1>採用裝飾模式擴展對象的功能比採用繼承方式更加靈活。
   2>可以設計出多個不同的具體裝飾類,創造出多個不同行爲的組合。
  缺點:
   1>增加了許多子類,如果過度使用會使程序變得很複雜。

4.3 裝飾器模式主要角色

  通常情況下,擴展一個類的功能會使用繼承方式來實現。但使用繼承方式的話,耦合度高,並且隨着擴展功能的增多,子類會變得很臃腫。如果使用組合關係來創建一個包裝對象(即裝飾對象)來包裹真實對象,並在保持真實對象的類結構不變的前提下,爲其提供額外的功能,這就是裝飾模式的目標。
  裝飾器角色如下:
  1>抽象構件角色,定義一個抽象接口以規範準備接收附加責任的對象。
  2>具體構件角色,實現抽象構件,通過裝飾角色爲其添加一些職責。
  3>抽象裝飾角色,繼承抽象構件,幷包含具體構件的實例,可以通過其子類擴展具體構件的功能。
  4>具體裝飾角色,實現抽象裝飾的相關方法,並給具體構件對象添加附加的責任。

4.4 裝飾器模式實現方式

  以學生爲例,進行體育運動時穿運動裝,上課時轉校服,示例代碼如下:

/*抽象構件角色*/
public interface Student {
	public void act();
}
/*具體構件角色*/
public class Jack implements Student{
	public Jack(){
	}
	public void act() {
		System.out.println("Jack開始做事");
	}
}
/*抽象裝飾角色*/
public class Decorator implements Student{
    private Student student;   
    public Decorator(Student student)
    {
        this.student=student;
    }   
    public void act()
    {
    	student.act();
    }
}
/*具體裝飾角色1:運動員*/
public class Player extends  Decorator{
	public Player(Student student) {
		super(student);
	}
    public void act()
    {
        super.act();
        addedFunction();
    }
    public void addedFunction()
    {
        System.out.println("要去打籃球,穿運動服");           
    }
}
/*具體裝飾角色2:上課的人*/
public class Learner extends  Decorator{
	public Learner(Student student) {
		super(student);
	}
    public void act()
    {
        super.act();
        addedFunction();
    }
    public void addedFunction()
    {
        System.out.println("要去上課,穿校服");           
    }
}
/*測試類*/
public class DecoratorTest {
    public static void main(String[] args) { 
    	Student student = new Jack();
    	Student player = new Player(student);
    	player.act();
    	Student learner = new Learner(student);
    	learner.act();
     }
}

  測試結果如下:

Jack開始做事
要去打籃球,穿運動服
Jack開始做事
要去上課,穿校服

4.5 裝飾器模式應用場景

  裝飾器模式通常適用的場景:
   1)當需要給一個現有類添加附加職責,而又不能採用生成子類的方法進行擴充時。
   2)當需要通過對現有的一組基本功能進行排列組合而產生非常多的功能時,採用繼承關係很難實現,而採用裝飾模式卻很好實現。
   3)當對象的功能要求可以動態地添加,也可以再動態地撤銷時。

五、外觀模式

5.1 外觀模式定義

  一種通過爲多個複雜的子系統提供一個一致的接口,而使這些子系統更加容易被訪問的模式。

5.2 外觀模式特點

  優點:
   1>降低了子系統與客戶端之間的耦合度,使得子系統的變化不會影響調用它的客戶類。
   2>對客戶屏蔽了子系統組件,減少了客戶處理的對象數目,並使得子系統使用起來更加容易。
   3>降低了大型軟件系統中的編譯依賴性,簡化了系統在不同平臺之間的移植過程,因爲編譯一個子系統不會影響其他的子系統,也不會影響外觀對象。
  缺點:
   1>不能很好地限制客戶使用子系統類。
   2>增加新的子系統可能需要修改外觀類或客戶端的源代碼,違背了“開閉原則”。

5.3 外觀模式主要角色

  外觀角色:爲多個子系統對外提供一個共同的接口。
  子系統角色:實現系統的部分功能,客戶可以通過外觀角色訪問它。
  客戶角色:通過一個外觀角色訪問各個子系統的功能。

5.4 外觀模式實現方式

  以上班族爲例,一個人早上起牀後,去上班前要做一系列的事情:穿衣、洗漱、坐公交等,示例代碼如下:

/*子系統1*/
public class Step1 {
    public void executeStep(){
    	System.out.println("穿衣服");  
    }
}
/*子系統2*/
public class Step2 {
    public void executeStep(){
    	System.out.println("洗漱");  
    }
}
/*子系統3*/
public class Step3 {
    public void executeStep(){
    	System.out.println("坐公交");  
    }
}
/*外觀*/
public class Employee {
	public Employee(){
		System.out.println("一個人上班的流程:"); 
	}
    Step1 step1 = new Step1();
    Step2 step2 = new Step2();
    Step3 step3 = new Step3();
    public void work()
    {
     	step1.executeStep();
        step2.executeStep();
        step3.executeStep();
    }
}
/*測試類,也是客戶*/
public class FacadeTest {
    public static void main(String[] args) { 
    	Employee employee = new Employee();
    	employee.work();
    }
}

  結果如下:

一個人上班的流程:
穿衣服
洗漱
坐公交

5.5 外觀模式應用場景

  外觀模式通常適用的場景:
   1)對分層結構系統構建時,使用外觀模式定義子系統中每層的入口點可以簡化子系統之間的依賴關係。
   2)當一個複雜系統的子系統很多時,外觀模式可以爲系統設計一個簡單的接口供外界訪問。
   3)當客戶端與多個子系統之間存在很大的聯繫時,引入外觀模式可將它們分離,從而提高子系統的獨立性和可移植性。

六、享元模式

6.1 享元模式定義

  運用共享技術來有効地支持大量細粒度對象的複用。它通過共享已經存在的又橡來大幅度減少需要創建的對象數量、避免大量相似類的開銷,從而提高系統資源的利用率。

6.2 享元模式特點

  優點:
   1>相同對象只要保存一份,這降低了系統中對象的數量,從而降低了系統中細粒度對象給內存帶來的壓力。
  缺點:
   1>爲了使對象可以共享,需要將一些不能共享的狀態外部化,這將增加程序的複雜性。
   2>讀取享元模式的外部狀態會使得運行時間稍微變長。

6.3 享元模式主要角色

  抽象享元角色:是所有的具體享元類的基類,爲具體享元規範需要實現的公共接口,非享元的外部狀態以參數的形式通過方法傳入。
  具體享元角色:實現抽象享元角色中所規定的接口。
  非享元角色:是不可以共享的外部狀態,它以參數的形式注入具體享元的相關方法中。
  享元工廠角色:負責創建和管理享元角色。當客戶對象請求一個享元對象時,享元工廠檢査系統中是否存在符合要求的享元對象,如果存在則提供給客戶;如果不存在的話,則創建一個新的享元對象。

6.4 享元模式實現方式

  此處以學生寫字爲例,有時需要用藍色筆寫字,有時需要用黑色筆寫字,第一次寫某顏色的字時,在文具盒中找出相應的筆,下次不用再從哪個文具盒中找,直接使用即可。示例代碼如下:

/*非享元角色*/
public class PenInfo {
    private String info;
    PenInfo(String info)
    {
        this.info=info;
    }
    public String getInfo()
    {
        return info;
    }
    public void setInfo(String info)
    {
        this.info=info;
    }
}
/*抽象享元角色*/
public interface  Pen {
	public void operation(PenInfo state);
}
/*具體享元角色1*/
public class BluePen implements Pen{
    private String key;
    BluePen(String key)
    {
        this.key=key;
        System.out.println(key+"顏色的筆從文具盒中找出!");
    }
    public void operation(PenInfo outState)
    {
        System.out.print("具體享元"+key+"被調用,");
        System.out.println("非享元信息是:"+outState.getInfo());
    }
}
/*具體享元角色2*/
public class BlackPen implements Pen{
    private String key;
    BlackPen(String key)
    {
        this.key=key;
        System.out.println(key+"顏色的筆從文具盒中找出!");
    }
    public void operation(PenInfo outState)
    {
        System.out.print("具體享元"+key+"被調用,");
        System.out.println("非享元信息是:"+outState.getInfo());
    }
}
/*享元工廠角色*/
public class PenFactory {
    private HashMap<String, Pen> pens=new HashMap<String, Pen>();
    public Pen getPen(String key)
    {
    	Pen pen=(Pen)pens.get(key);
        if(pen!=null)
        {
            System.out.println(key+"顏色的筆已經存在,可直接使用!");
        }
        else
        {
        	if("blue".equals(key)){
               pen=(Pen) new BluePen(key);
            }else{
               pen=(Pen) new BlackPen(key);
            }
        		
        	pens.put(key, pen);
        }
        return pen;
    }
}
/*測試類*/
public class PenTest {
    public static void main(String[] args)
    {
    	PenFactory factory=new PenFactory();
        Pen pen1=factory.getPen("blue");
        Pen pen2=factory.getPen("blue");
        Pen pen3=factory.getPen("blue");
        Pen pen4=factory.getPen("black");
        Pen pen5=factory.getPen("black");       
        pen1.operation(new PenInfo("第1次使用blue筆"));       
        pen2.operation(new PenInfo("第2次使用blue筆"));       
        pen3.operation(new PenInfo("第3次使用blue筆"));       
        pen4.operation(new PenInfo("第1次使用black筆"));       
        pen5.operation(new PenInfo("第2次使用black筆"));
    }
}

  測試結果如下:

blue顏色的筆從文具盒中找出!
blue顏色的筆已經存在,可直接使用!
blue顏色的筆已經存在,可直接使用!
black顏色的筆從文具盒中找出!
black顏色的筆已經存在,可直接使用!
具體享元blue被調用,非享元信息是:第1次使用blue筆
具體享元blue被調用,非享元信息是:第2次使用blue筆
具體享元blue被調用,非享元信息是:第3次使用blue筆
具體享元black被調用,非享元信息是:第1次使用black筆
具體享元black被調用,非享元信息是:第2次使用black筆

6.5 享元模式應用場景

  享元模式通常適用的場景:
   1)系統中存在大量相同或相似的對象,這些對象耗費大量的內存資源。
   2)大部分的對象可以按照內部狀態進行分組,且可將不同部分外部化,這樣每一個組只需保存一個內部狀態。
   3)由於享元模式需要額外維護一個保存享元的數據結構,所以應當在有足夠多的享元實例時才值得使用享元模式。

七、代理模式

7.1 代理模式定義

  由於某些原因需要給某對象提供一個代理以控制對該對象的訪問。

7.2 代理模式特點

  優點:
   1>代理模式在客戶端與目標對象之間起到一箇中介作用和保護目標對象的作用。
   2>代理對象可以擴展目標對象的功能。
   3>代理模式能將客戶端與目標對象分離,在一定程度上降低了系統的耦合度。
  缺點:
   1>在客戶端和目標對象之間增加一個代理對象,會造成請求處理速度變慢。
   2>增加了系統的複雜度。

7.3 代理模式主要角色

  抽象主題類:通過接口或抽象類聲明真實主題和代理對象實現的業務方法。
  真實主題類:實現了抽象主題中的具體業務,是代理對象所代表的真實對象,是最終要引用的對象。
  代理類:提供了與真實主題相同的接口,其內部含有對真實主題的引用,它可以訪問、控制或擴展真實主題的功能。

7.4 代理模式實現方式

  代碼模式有兩種實現方式:靜態代理和動態代理。

7.4.1 靜態代理

  靜態代理可以在不修改被代理對象的基礎上,通過擴展代理類,進行一些功能的附加與增強。值得注意的是,代理類和被代理類應該共同實現一個接口,或者是共同繼承某個類。比如要買電影票,但又不想去電影院買,這時就可以通過購票APP等第三方"代理"來購買。示例代碼如下:

/*抽象主題類,電影*/
public interface Movie {
    public void buyMovieTicket();
}
/*真實主題類,第三方購票APP*/
public class TaoPiaoPiao implements Movie {
	public void buyMovieTicket() {	
		System.out.println("淘票票幫您購買電影票"); 
	}
}
/*代理類,通過第三方APP購票*/
public class Proxy implements Movie{
	private TaoPiaoPiao movie;
	public void buyMovieTicket() {
		if(movie == null){
		    movie=new TaoPiaoPiao();
		}
		System.out.println("登錄淘票票"); 
		movie.buyMovieTicket();
		System.out.println("淘票票向你推薦爆米花、可樂");
	}
}
/*測試類*/
public class ProxyTest {
	public static void main(String[] args) { 
		Proxy proxy=new Proxy();
        proxy.buyMovieTicket();
	}
}

  示例結果如下:

登錄淘票票
淘票票幫您購買電影票
淘票票向你推薦爆米花、可樂

7.4.2 動態代理

  動態代理代理依靠反射來實現,代理類在JVM運行時動態生成,而不是編譯期就能確定。仍以上面的代碼爲例,區別在於代理類和測試類。示例代碼如下:

/*動態代理類*/
public class Proxy1{	
    private TaoPiaoPiao movie;
    public Proxy1(TaoPiaoPiao movie) {
        this.movie = movie;
    }
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(movie.getClass().getClassLoader(), movie.getClass().getInterfaces(), new InvocationHandler() {

			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				if(movie == null){
				    movie=new TaoPiaoPiao();
				}
				System.out.println("登錄淘票票"); 
				movie.buyMovieTicket();
				System.out.println("淘票票向你推薦爆米花、可樂");
				return null;
			}
        });
    }
}
/*測試類*/
public class ProxyTest {
	public static void main(String[] args) { 
        TaoPiaoPiao movie = new TaoPiaoPiao();
        Movie dynamicProxy = (Movie) new Proxy1(movie).getProxyInstance();
        dynamicProxy.buyMovieTicket();
	}
}

7.5 代理模式應用場景

  代理模式通常適用的場景:
   1)虛擬代理,這種方式通常用於要創建的目標對象開銷很大時。
   2)安全代理,這種方式通常用於控制不同種類客戶對真實對象的訪問權限。
   3)智能指引,主要用於調用目標對象時,代理附加一些額外的處理功能。例如,增加計算真實對象的引用次數的功能,這樣當該對象沒有被引用時,就可以自動釋放它。
  參考資料:結構型模式概述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章