摘要:簡介代理模式和裝飾者模式是兩種常見的設計模式。這里通過構造函數的參數將被代理對象傳入到代理中,也可以通過其它方式,如提供一個方法。下面是的代碼輸出首先依然是先創建一個需要被代理的對象,然后把它傳入到的構造函數中。
簡介
代理模式和裝飾者模式是兩種常見的設計模式。代理模式是為其它對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾者來包裹真實的對象。
因為這兩種模式比較相似,所以把它們放在一起做個比較與總結。
代理模式代理模式包含代理對象和被代理對象,類圖如下:
代理對象 Proxy 和被代理對象 RealSubject 都繼承了 Subject 接口。客戶端調用 Proxy 的方法,而 Proxy 則把具體操作委托給 RealSubject 執行。下面是代碼實現:
interface Subject { void doAction(); } class RealSubject implements Subject { @Override public void doAction() { System.out.println("RealSubject#doAction"); } } class Proxy implements Subject { private Subject subject; public Proxy(Subject subject) { this.subject = subject; } @Override public void doAction() { subject.doAction(); } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); Subject proxy = new Proxy(realSubject); proxy.doAction(); } } 輸出:RealSubject#doAction
在 Client 中,首先創建了一個 realSubject 對象,然后創建一個代理對象 proxy 并且把 realSubject
對象通過構造器傳入進去。最后調用代理對象的 doAction,實際執行的是 realSubject 的對應方法。這里通過構造函數的參數將被代理對象傳入到代理中,也可以通過其它方式,如提供一個 setSubject 方法。
上面的代理模式,代理對象和被代理對象需要實現相同的接口,所以如果要代理其它接口的對象需要寫一個新的代理類。Java 提供了動態代理的功能,可以簡化我們的代碼。
動態代理動態代理可以在運行期生成所需要的代理對象,看下面的代碼:
class DynamicProxy implements InvocationHandler { // 被代理對象的引用 private Object obj; public DynamicProxy(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(obj, args); return result; } }
類 DynamicProxy 實現了 InvocationHandler 接口,這個接口中有一個 invoke 方法,被代理的對象的任何方法都是在 invoke 中調用。下面是 Client 的代碼:
public class TestDelegate { public static void main(String[] args) { Subject realSubject = new RealSubject(); DynamicProxy dynamicProxy = new DynamicProxy(realSubject); ClassLoader loader = realSubject.getClass().getClassLoader(); Subject proxy = (Subject) Proxy.newProxyInstance(loader, new Class[]{Subject.class}, dynamicProxy); proxy.doAction(); } } 輸出:RealSubject#doAction
首先依然是先創建一個需要被代理的對象 realSubject,然后把它傳入到 DynamicProxy 的構造函數中。這個 dynamicProxy 還不是我們需要的代理,畢竟它沒有實現 Subject 接口。下面通過 Proxy.newProxyInstance 創建了一個 Subject 對象,也就是最終的代理對象。
通過動態代理,創建一個實現了 InvocationHandler 接口的 DynamicProxy 類,通過這個類可以在運行期為各種對象創建對應的代理,比靜態代理方便了很多。
裝飾者模式裝飾者模式是為了給已有的對象增加一些邏輯,但是不改變已有對象的代碼,下面是類圖:
從上圖可以看出,裝飾者 Decorator與需要被裝飾的對象 ContcreteComponent 實現了相同的接口。具體怎么裝飾則由 Decorator 的子類 ConcreteDecorator 決定。
Java 中使用裝飾者模式的一個典型的例子是 I/O 對象的創建,比如創建一個 BufferedInputStream 時:
InputStream in = ... InputStream input = new BufferedInputStream(in);
BufferedInputStream 繼承于 FilterInputStream,這個 FilterInputStream 相當于裝飾者模式中的 Decorator,它繼承了 InputStream 接口。BufferedInputStream 則是一個具體的裝飾類,其它還有 DataInputStream 以及 ByteArrayInputStream 等。而傳給 BufferedInputstream 的對象 in 則是需要被裝飾者。裝飾者對被裝飾者進行了功能的擴展,但是又不需要修改被裝飾者的相應代碼,符合“開閉原則”,即對于修改是封閉的,對于擴展則是開放的。
如果是為了給某個類提供更多的功能,繼承是一種方案。但是,如果我們的功能有很多種組合,那么為每種組合編寫一個繼承的類可能需要創建太多的子類。而裝飾者模式則可以解決這個問題,只需要為每個功能編寫一個裝飾類,在運行時組合不同的對象即可實現所需的功能組合。
總結代理模式和裝飾者模式有著很多的應用,這兩者具有一定的相似性,都是通過一個新的對象封裝原有的對象。二者之間的差異在于代理模式是為了實現對象的控制,可能被代理的對象難以直接獲得或者是不想暴露給客戶端,而裝飾者模式是繼承的一種替代方案,在避免創建過多子類的情況下為被裝飾者提供更多的功能。
如果我的文章對您有幫助,不妨點個贊支持一下(^_^)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68343.html
摘要:聲明這個系列為閱讀設計模式與開發實踐曾探著一書的讀書筆記裝飾者模式的定義裝飾者模式能夠在不改變對象自身的基礎上,在程序運行期間給對像動態的添加職責。與繼承相比,裝飾者是一種更輕便靈活的做法。裝飾者模式的作用就是為對象動態的加入某些行為。 聲明:這個系列為閱讀《JavaScript設計模式與開發實踐》 ----曾探@著一書的讀書筆記 裝飾者模式的定義: 裝飾者(decorator)模式能...
摘要:下面總結了它倆的異同相同點都需要實現同一個接口或者繼承同一個抽象類,并且代理角色和裝飾角色都持有被代理角色和構件角色的引用。 寫完上一篇之后有小伙伴問我有沒有寫過代理模式,想看看我的理解。原本我的設計模式系列是按照創建型-行為型-結構型的順序寫下去的,既然小伙伴誠心誠意了,我就大發慈悲的穿插一篇代理模式。開玩笑,題外話。 說起代理模式,就不由得想起經紀人,說起經紀人,就想起了...對,...
摘要:相關設計模式裝飾者模式和代理模式裝飾者模式關注再一個對象上動態添加方法代理模式關注再對代理對象的控制訪問,可以對客戶隱藏被代理類的信息裝飾著模式和適配器模式都叫包裝模式關于新職責適配器也可以在轉換時增加新的職責,但主要目的不在此。 0x01.定義與類型 定義:裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的...
摘要:與其它模式的異同適配器模式不會改變原有接口,這一點與裝飾者模式和代理模式類似。代理模式適配器模式與代理模式最相似,同樣都是創建一個新對象包裝一次,實現對本體的調用。外觀模式外觀模式與適配器模式最大的區別,是定義了一個新的接口。 showImg(https://segmentfault.com/img/bVbul8d?w=800&h=600); 適配器模式:將一個類(對象)的接口(方法或...
閱讀 1026·2021-11-23 09:51
閱讀 2344·2021-10-08 10:22
閱讀 2544·2021-09-29 09:35
閱讀 854·2021-09-22 15:20
閱讀 2859·2019-08-30 15:53
閱讀 2413·2019-08-30 13:55
閱讀 1097·2019-08-29 17:27
閱讀 2870·2019-08-29 17:26