裝飾器模式和代理模式的區別


參考:

https://www.cnblogs.com/yanggb/p/10952843.html

https://www.cnblogs.com/xiaolovewei/p/7751332.html

 

 

 

 

 

裝飾器模式和代理模式的區別

代理模式和裝飾器模式很像,這里用【到咖啡館喝咖啡】作例子來講解。

基礎實現

定義一個咖啡的接口。

復制代碼
public interface Coffee {
    /**
     * 打印當前咖啡里有什么
     */
    void printMaterial();
}
復制代碼

定義一個苦咖啡的實現。

復制代碼
public class BitterCoffee implements Coffee {
    @Override
    public void printMaterial() {
        System.out.println("咖啡");
    }
}
復制代碼

定義一個默認的點咖啡邏輯。

@Test
public void orderCoffee {
    Coffee coffee = new BitterCoffee();
    coffee.printMaterial(); // 咖啡
}

裝飾器模式

你喝了一口咖啡,覺得有點苦,於是你就想加點糖。

定義一個咖啡裝飾器(加糖)。

復制代碼
public class CoffeeDecorator implements Coffee {
    /**
     * 持有一個咖啡對象
     */
    private final Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public void printMaterial() {
        System.out.println("糖");
        this.coffee.printMaterial();
    }
}
復制代碼

定義一個咖啡加糖的應用邏輯。

復制代碼
@Test
public void addSugerIntoCoffee {
    Coffee coffee = new BitterCoffee(); // 點了一杯苦咖啡
    coffee = new SugarDecorator(coffee); // 給咖啡加了點糖
    coffee.printMaterial(); // 糖 咖啡
}
復制代碼

裝飾器適用場景:我有一個對象,但是這個對象的功能不能使我滿意(咖啡太苦了),我就拿裝飾器給他裝飾一下(給咖啡加糖)。

代理模式(靜態代理)

約好的朋友來了,要給她點一杯咖啡,你知道咖啡很苦,決定直接點一杯加了糖的咖啡給她。

定義一個加糖咖啡的類。

復制代碼
public class CoffeeProxy implements Coffee {
    private final Coffee coffee;

    public CoffeeProxy() {
        this.coffee = new BitterCoffee();
    }

    @Override
    public void printMaterial() {
        System.out.println("糖");
        this.coffee.printMaterial();
    }
}
復制代碼

然后定義一個點加糖咖啡的邏輯。

@Test
public void addSugerIntoCoffee {
    Coffee coffee = new CoffeeProxy();
    coffee.printMaterial(); // 糖 咖啡
}

裝飾器和代理模式的區別

對裝飾器模式來說,裝飾者(Decorator)和被裝飾者(Decoratee)都實現一個接口。對代理模式來說,代理類(Proxy Class)和真實處理的類(Real Class)都實現同一個接口。此外,不論我們使用哪一個模式,都可以很容易地在真實對象的方法前面或者后面加上自定義的方法。

在上面的例子中,裝飾器模式是使用的調用者從外部傳入的被裝飾對象(coffee),調用者只想要你把他給你的對象裝飾(加強)一下。而代理模式使用的是代理對象在自己的構造方法里面new的一個被代理的對象,不是調用者傳入的。調用者不知道你找了其他人,他也不關心這些事,只要你把事情做對了即可。

裝飾器模式關注於在一個對象上動態地添加方法,而代理模式關注於控制對對象的訪問。換句話說,用代理模式,代理類可以對它的客戶隱藏一個對象的具體信息。因此當使用代理模式的時候,我們常常在一個代理類中創建一個對象的實例;當使用裝飾器模式的時候,我們通常的做法是將原始對象作為一個參數傳給裝飾器的構造器。

裝飾器模式和代理模式的使用場景不一樣,比如IO流使用的是裝飾者模式,可以層層增加功能。而代理模式則一般是用於增加特殊的功能,有些動態代理不支持多層嵌套。

代理和裝飾其實從另一個角度更容易去理解兩個模式的區別:代理更多的是強調對對象的訪問控制,比如說,訪問A對象的查詢功能時,訪問B對象的更新功能時,訪問C對象的刪除功能時,都需要判斷對象是否登陸,那么我需要將判斷用戶是否登陸的功能抽提出來,並對A對象、B對象和C對象進行代理,使訪問它們時都需要去判斷用戶是否登陸,簡單地說就是將某個控制訪問權限應用到多個對象上;而裝飾器更多的強調給對象加強功能,比如說要給只會唱歌的A對象添加跳舞功能,添加說唱功能等,簡單地說就是將多個功能附加在一個對象上。

所以,代理模式注重的是對對象的某一功能的流程把控和輔助,它可以控制對象做某些事,重心是為了借用對象的功能完成某一流程,而非對象功能如何。而裝飾模式注重的是對對象功能的擴展,不關心外界如何調用,只注重對對象功能加強,裝飾后還是對象本身。

總結

對於代理類,如何調用對象的某一功能是思考重點,而不需要兼顧對象的所有功能;對於裝飾類,如何擴展對象的某一功能是思考重點,同時也需要兼顧對象的其他功能,因為再怎么裝飾,本質也是對象本身,要擔負起對象應有的職責,被裝飾者的職責一旦增加,作為裝飾類也需要有相應的擴展,必然會造成編碼的負擔。

設計模式本身是為了提升代碼的可擴展性,靈活應用即可,不必生搬硬套,非要分出個所以然來,裝飾器模式和代理模式的區別也是如此。

 

 

 

 

 

 

 

代理模式和裝飾者模式的區別

轉載自:http://www.cnblogs.com/jaredlam/archive/2011/11/08/2241089.html

學習AOP時,教材上面都說使用的是動態代理,可是在印象中代理模式一直都是控制訪問什么的,怎么又動態增加行為了,動態增加行為不是裝飾器模式嗎?於是 找了很多資料,想弄清楚這兩者之間到底有什么區別。結果發現這一篇英文文章講的很清晰,就翻譯一下,供參考。       

        首先,讓我們先看一下下面的這兩個UML類圖,他們分別描述了裝飾器模式和代理模式的基本實現。

                    

                     

        這兩個圖可能使我們產生困惑。這兩個設計模式看起來很像。對裝飾器模式來說,裝飾者(decorator)和被裝飾者(decoratee)都實現同一個 接口。對代理模式來說,代理類(proxy class)和真實處理的類(real class)都實現同一個接口。此外,不論我們使用哪一個模式,都可以很容易地在真實對象的方法前面或者后面加上自定義的方法。

        然而,實際上,在裝飾器模式和代理模式之間還是有很多差別的。裝飾器模式關注於在一個對象上動態的添加方法,然而代理模式關注於控制對對象的訪問。換句話 說,用代理模式,代理類(proxy class)可以對它的客戶隱藏一個對象的具體信息。因此,當使用代理模式的時候,我們常常在一個代理類中創建一個對象的實例。並且,當我們使用裝飾器模 式的時候,我們通常的做法是將原始對象作為一個參數傳給裝飾者的構造器。

        我們可以用另外一句話來總結這些差別:使用代理模式,代理和真實對象之間的的關系通常在編譯時就已經確定了,而裝飾者能夠在運行時遞歸地被構造。    

代理模式:

復制代碼
復制代碼
//代理模式
public class Proxy implements Subject{

private Subject subject;
public Proxy(){
//關系在編譯時確定
subject = new RealSubject();
}
public void doAction(){
….
subject.doAction();
….
}
}
復制代碼
復制代碼
復制代碼
復制代碼
//代理的客戶
public class Client{
public static void main(String[] args){
//客戶不知道代理委托了另一個對象
Subject subject = new Proxy();

}
}
復制代碼
復制代碼

裝飾模式:

復制代碼
復制代碼
//裝飾器模式
public class Decorator implements Component{
private Component component;
public Decorator(Component component){
this.component = component
}
public void operation(){
….
component.operation();
….
}
}
復制代碼
復制代碼
復制代碼
復制代碼
//裝飾器的客戶
public class Client{
public static void main(String[] args){
//客戶指定了裝飾者需要裝飾的是哪一個類
Component component = new Decorator(new ConcreteComponent());

}
}
復制代碼

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM