最近在學習Spring源碼,尤其是在學習FactoryBean的時候,有涉及到裝飾器模式,再結合自己之前學習的設計模式,代理模式覺得和裝飾器模式很相似,但是仔細研究後有各有不同,在這篇文章中整理下,希望可以幫助到需要的朋友。
裝飾器模式
定義:動态地給一個對象添加一些額外的職責,同時又不改變其結構,就增加功能來說裝飾模式比生成子類更為靈活。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM1czX3xCZlhXam9VbsUmepNXZy9CXwJWZ3xCdh1mcvZ2Lc1zaHRGcWdUYuVzVa9GczoVdG1mWfVGc5RHLwIzX39GZhh2csATMflHLwEzX4xSZz91ZsAzMfRHLGZkRGZkRfJ3bs92YskmNhVTYykVNQJVMRhXVEF1X0hXZ0xiNx8VZ6l2cssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3ATN5UTNzEDZmhTM1MTZyYzX5MDOxETM5IzLcdDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
Component是定義一個對象接口,可以給這些對象動态的添加職責,ConcreteComponent是定義一個具體的對象,也可以給這個對象動态添加一些職責。Decorator,裝飾抽象類,繼承Component,從外類來擴充Component類的功能,但對于Component來說,是無需知道Decorator的存在的。至于ConcreteDecorator就是具體的裝飾對象,起到給Component添加職責的功能。
主要解決:一般的,我們為了擴充一個類經常使用繼承方式實作,由于繼承為類引入靜态特征,并且随着擴充功能的增多,子類會很膨脹。
何時使用:在不想增加很多子類的情況下擴充類。
如何解決:将具體功能職責劃分,同時繼承裝飾者模式。
關鍵代碼: 1、Component 類充當抽象角色,不應該具體實作。 2、修飾類引用和繼承 Component 類,具體擴充類重寫父類方法。
優點:裝飾類和被裝飾類可以獨立發展,不會互相耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動态擴充一個實作類的功能。
缺點:多層裝飾比較複雜。
使用場景: 1、擴充一個類的功能。 2、動态增加功能,動态撤銷。
注意事項:可代替繼承。
實作代碼
//充當抽象角色,不應該具體實作
public interface Component {
void Operation();
}
//有一個具體的對象
public class ConcreteComponent implements Component {
@Override
public void Operation() {
System.out.println("對象具體操作");
}
}
//裝飾抽象類繼承Component
public abstract class Decorator implements Component {
protected Component component;
public void setComponent(Component component) {
this.component = component;
}
@Override
public void Operation() {
if (component != null) {
component.Operation();
}
}
}
//裝飾的具體實作類
public class ConcreteDecoratorA extends Decorator {
@Override
public void Operation() {
super.Operation();
System.out.println("具體裝飾對象A的操作");
}
}
public class ConcreteDecoratorB extends Decorator {
@Override
public void Operation() {
super.Operation();
System.out.println("具體裝飾對象B的操作");
}
}
public static void main(String[] args) {
ConcreteComponent component = new ConcreteComponent();
ConcreteDecoratorA decoratorA = new ConcreteDecoratorA();
ConcreteDecoratorB decoratorB = new ConcreteDecoratorB();
//裝飾模式:首先用ConcreteComponent執行個體化對象component,
//然後用ConcreteDecoratorA的執行個體化對象decoratorA包裝component
//最後用ConcreteDecoratorB的執行個體化對象decoratorB包裝decoratorA
decoratorA.setComponent(component);
decoratorB.setComponent(decoratorA);
decoratorB.Operation();
}
原理:裝飾模式利用 setComponent來對對象進行包裝,這樣每個裝飾對象的實作和如何使用這個對象分離開了。每個裝飾對象隻關心自己的功能,不需要關心如何被添加到哦對象鍊中。
代理模式
定義:為其他對象提供一種代理以控制對這個對象的通路。
主要解決:在直接通路對象時帶來的問題,比如說:要通路的對象在遠端的機器上。在面向對象系統中,有些對象由于某些原因(比如對象建立開銷很大,或者某些操作需要安全控制,或者需要程序外的通路),直接通路會給使用者或者系統結構帶來很多麻煩,我們可以在通路此對象時加上一個對此對象的通路層。
何時使用:想在通路一個類時做一些控制。
如何解決:增加中間層。
關鍵代碼:實作與被代理類組合。
應用執行個體: 1、Windows 裡面的快捷方式。 2、豬八戒去找高翠蘭結果是孫悟空變的,可以這樣了解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實作了這個接口,豬八戒通路高翠蘭的時候看不出來這個是孫悟空,是以說孫悟空是高翠蘭代理類。 3、買火車票不一定在火車站買,也可以去代售點。 4、一張支票或銀行存單是賬戶中資金的代理。支票在市場交易中用來代替現金,并提供對簽發人賬号上資金的控制。 5、spring aop。
優點: 1、職責清晰。 2、高擴充性。 3、智能化。
缺點: 1、由于在用戶端和真實主題之間增加了代理對象,是以有些類型的代理模式可能會造成請求的處理速度變慢。 2、實作代理模式需要額外的工作,有些代理模式的實作非常複雜。
使用場景:按職責來劃分,通常有以下使用場景: 1、遠端代理。 2、虛拟代理。 3、Copy-on-Write 代理。 4、保護(Protect or Access)代理。 5、Cache代理。 6、防火牆(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
實作代碼
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("真實的請求");
}
}
public class Proxy implements Subject {
private Subject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
System.out.println("代理請求也被執行");
}
}
public class Demo {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
}
裝飾器模式和代理模式相同點以及不同點
相同點
兩種從設計模式分類來看都屬于結構型,因為兩者均使用了組合關系。其次兩者都能實作對對象方法進行增強處理的效果。
不同點
代理模式,注重對對象某一功能的流程把控和輔助。它可以控制對象做某些事,重心是為了借用對象的功能完成某一流程,而非對象功能如何。
裝飾模式,注重對對象功能的擴充,它不關心外界如何調用,隻注重對對象功能的加強,裝飾後還是對象本身。
舉個例子說明兩者不同之處,代理和裝飾其實從另一個角度更容易去了解兩個模式的差別:代理更多的是強調對對象的通路控制,比如說,通路A對象的查詢功能時,通路B對象的更新功能時,通路C對象的删除功能時,都需要判斷對象是否登陸,那麼我需要将判斷使用者是否登陸的功能抽提出來,并對A對象、B對象和C對象進行代理,使通路它們時都需要去判斷使用者是否登陸,簡單地說就是将某個控制通路權限應用到多個對象上;而裝飾器更多的強調給對象加強功能,比如說要給隻會唱歌的A對象添加跳舞功能,添加說唱功能等,簡單地說就是将多個功能附加在一個對象上。
是以,代理模式注重的是對對象的某一功能的流程把控和輔助,它可以控制對象做某些事,重心是為了借用對象的功能完成某一流程,而非對象功能如何。而裝飾模式注重的是對對象功能的擴充,不關心外界如何調用,隻注重對對象功能加強,裝飾後還是對象本身。