摘要:相關(guān)設(shè)計(jì)模式裝飾者模式和代理模式裝飾者模式關(guān)注再一個(gè)對(duì)象上動(dòng)態(tài)添加方法代理模式關(guān)注再對(duì)代理對(duì)象的控制訪問(wèn),可以對(duì)客戶(hù)隱藏被代理類(lèi)的信息裝飾著模式和適配器模式都叫包裝模式關(guān)于新職責(zé)適配器也可以在轉(zhuǎn)換時(shí)增加新的職責(zé),但主要目的不在此。
0x01.定義與類(lèi)型
定義:裝飾模式指的是在不必改變?cè)?lèi)文件和使用繼承的情況下,動(dòng)態(tài)地?cái)U(kuò)展一個(gè)對(duì)象的功能。它是通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,也就是裝飾來(lái)包裹真實(shí)的對(duì)象。
特點(diǎn):
裝飾對(duì)象和真實(shí)對(duì)象有相同的接口。這樣客戶(hù)端對(duì)象就能以和真實(shí)對(duì)象相同的方式和裝飾對(duì)象交互。
裝飾對(duì)象包含一個(gè)真實(shí)對(duì)象的引用(reference)
裝飾對(duì)象接受所有來(lái)自客戶(hù)端的請(qǐng)求。它把這些請(qǐng)求轉(zhuǎn)發(fā)給真實(shí)的對(duì)象。
裝飾對(duì)象可以在轉(zhuǎn)發(fā)這些請(qǐng)求以前或以后增加一些附加功能。這樣就確保了在運(yùn)行時(shí),不用修改給定對(duì)象的結(jié)構(gòu)就可以在外部增加附加的功能。在面向?qū)ο蟮脑O(shè)計(jì)中,通常是通過(guò)繼承來(lái)實(shí)現(xiàn)對(duì)給定類(lèi)的功能擴(kuò)展。
類(lèi)型:結(jié)構(gòu)型
UML類(lèi)圖
樣例實(shí)現(xiàn)
/** * 組件類(lèi)接口 */ public interface IComponent { void operation(); } /** * 具體組件類(lèi)的具體業(yè)務(wù)邏輯實(shí)現(xiàn) */ public class Component implements IComponent { @Override public void operation() { System.out.println("component operation!"); } } /** * 裝飾器的抽象類(lèi) */ public abstract class ADecorator implements IComponent { /** * 關(guān)鍵在于這個(gè)組合組件接口對(duì)象 */ private IComponent component; public ADecorator(IComponent component) { this.component = component; } @Override public void operation () { component.operation(); } } /** * 裝飾器具體實(shí)現(xiàn)1 */ public class Decorator1 extends ADecorator { public Decorator1(IComponent component) { super(component); } @Override public void operation() { super.operation(); System.out.println("decorator1"); } } /** * 裝飾器具體實(shí)現(xiàn)2 */ public class Decorator2 extends ADecorator { public Decorator2(IComponent component) { super(component); } @Override public void operation() { super.operation(); System.out.println("decorator2"); } }
測(cè)試與應(yīng)用類(lèi)
/** * 應(yīng)用與測(cè)試類(lèi) */ public class Test { public static void main(String[] args) { //應(yīng)用類(lèi) IComponent component; //初始化 component = new Component(); //裝飾 component = new Decorator1(component); component = new Decorator2(component); //具體方法的調(diào)用 component.operation(); } }
輸出結(jié)果
component operation! decorator1 decorator2
裝飾著模式中的各組件:
抽象構(gòu)件(IComponent)角色:給出一個(gè)抽象接口,以規(guī)范準(zhǔn)備接收附加責(zé)任的對(duì)象。
具體構(gòu)件(Component)角色:定義一個(gè)將要接收附加責(zé)任的類(lèi)。
裝飾(ADecorator)角色:持有一個(gè)構(gòu)件(IComponent)對(duì)象的實(shí)例,并定義一個(gè)與抽象構(gòu)件接口一致的接口。
具體裝飾(Decorator1/Decorator2)角色:負(fù)責(zé)給構(gòu)件對(duì)象“貼上”附加的責(zé)任。
0x02.使用場(chǎng)景需要擴(kuò)展一個(gè)類(lèi)的功能,或給一個(gè)類(lèi)添加附加職責(zé)。
需要?jiǎng)討B(tài)的給一個(gè)對(duì)象添加功能,這些功能可以再動(dòng)態(tài)的撤銷(xiāo)。
需要增加由一些基本功能的排列組合而產(chǎn)生的非常大量的功能,從而使繼承關(guān)系變的不現(xiàn)實(shí)。
當(dāng)不能采用生成子類(lèi)的方法進(jìn)行擴(kuò)充時(shí)。一種情況是,可能有大量獨(dú)立的擴(kuò)展,為支持每一種組合將產(chǎn)生大量的子類(lèi),使得子類(lèi)數(shù)目呈爆炸性增長(zhǎng)。另一種情況可能是因?yàn)轭?lèi)定義被隱藏,或類(lèi)定義不能用于生成子類(lèi)。
0x03.優(yōu)點(diǎn)Decorator模式與繼承關(guān)系的目的都是要擴(kuò)展對(duì)象的功能,但是Decorator可以提供比繼承更多的靈活性。
通過(guò)使用不同的具體裝飾類(lèi)以及這些裝飾類(lèi)的排列組合,設(shè)計(jì)師可以創(chuàng)造出很多不同行為的組合。
符合開(kāi)閉原則
0x04.缺點(diǎn)這種比繼承更加靈活機(jī)動(dòng)的特性,也同時(shí)意味著更加多的復(fù)雜性。
裝飾模式會(huì)導(dǎo)致設(shè)計(jì)中出現(xiàn)許多小類(lèi),如果過(guò)度使用,會(huì)使程序變得很復(fù)雜。
裝飾模式是針對(duì)抽象組件(Component)類(lèi)型編程。但是,如果你要針對(duì)具體組件編程時(shí),就應(yīng)該重新思考你的應(yīng)用架構(gòu),以及裝飾者是否合適。當(dāng)然也可以改變Component接口,增加新的公開(kāi)的行為,實(shí)現(xiàn)“半透明”的裝飾者模式。在實(shí)際項(xiàng)目中要做出最佳選擇
0x05.舉例實(shí)現(xiàn)裝飾著模式我們買(mǎi)煎餅果子可以選擇加香腸,還是加雞蛋。煎餅果子就是我們的組件類(lèi),而加雞蛋加培根則是裝飾者的具體實(shí)現(xiàn)類(lèi).
裝飾者模式Java實(shí)現(xiàn)
/** * 煎餅的抽象類(lèi),也就是組建類(lèi) */ public abstract class ABattercake { /** * 最后的描述 * @return */ protected abstract String getDesc (); /** * 總共的價(jià)格 * @return */ protected abstract int cost (); } /** * 煎餅的具體實(shí)現(xiàn) */ public class Battercake extends ABattercake { @Override protected String getDesc() { return "煎餅"; } @Override protected int cost() { return 8; } } /** * 裝飾著的抽象類(lèi) */ public abstract class AbstractDecorator extends ABattercake { //組合的煎餅對(duì)象 private ABattercake aBattercake; public AbstractDecorator(ABattercake aBattercake) { this.aBattercake = aBattercake; } protected abstract void doSomething(); @Override protected String getDesc() { return aBattercake.getDesc(); } @Override protected int cost() { return aBattercake.cost(); } } /** * 裝飾者的具體實(shí)現(xiàn) */ public class EggDecorator extends AbstractDecorator { public EggDecorator(ABattercake aBattercake) { super(aBattercake); } @Override protected void doSomething() { } @Override protected String getDesc() { return super.getDesc() + " 加一個(gè)雞蛋"; } @Override protected int cost() { return super.cost() + 1; } } /** * 裝飾者的具體實(shí)現(xiàn) */ public class SausageDecorator extends AbstractDecorator { public SausageDecorator(ABattercake aBattercake) { super(aBattercake); } @Override protected void doSomething() { } @Override protected String getDesc() { return super.getDesc() + " 加一根香腸"; } @Override protected int cost() { return super.cost() + 2; } }
應(yīng)用的測(cè)試類(lèi)
public class Test { public static void main(String[] args) { ABattercake aBattercake; aBattercake = new Battercake(); aBattercake = new EggDecorator(aBattercake); aBattercake = new EggDecorator(aBattercake); aBattercake = new SausageDecorator(aBattercake); System.out.println(aBattercake.getDesc() + "銷(xiāo)售價(jià)格:" + aBattercake.cost()); } }
輸入結(jié)果
煎餅 加一個(gè)雞蛋 加一個(gè)雞蛋 加一根香腸銷(xiāo)售價(jià)格:12
樣例UML類(lèi)圖
注意:裝飾者最上層的類(lèi)是否使用抽象類(lèi),這個(gè)是看業(yè)務(wù)的。
0x06.相關(guān)設(shè)計(jì)模式
裝飾者模式和代理模式
裝飾者模式:關(guān)注再一個(gè)對(duì)象上動(dòng)態(tài)添加方法
代理模式:關(guān)注再對(duì)代理對(duì)象的控制訪問(wèn),可以對(duì)客戶(hù)隱藏被代理類(lèi)的信息
裝飾著模式和適配器模式
都叫包裝模式
關(guān)于新職責(zé):適配器也可以在轉(zhuǎn)換時(shí)增加新的職責(zé),但主要目的不在此。裝飾者模式主要是給被裝飾者增加新職責(zé)的。
關(guān)于原接口:適配器模式是用新接口來(lái)調(diào)用原接口,原接口對(duì)新系統(tǒng)是不可見(jiàn)或者說(shuō)不可用的。裝飾者模式原封不動(dòng)的使用原接口,系統(tǒng)對(duì)裝飾的對(duì)象也通過(guò)原接口來(lái)完成使用。(增加新接口的裝飾者模式可以認(rèn)為是其變種--“半透明”裝飾者)
關(guān)于其包裹的對(duì)象:適配器是知道被適配者的詳細(xì)情況的(就是那個(gè)類(lèi)或那個(gè)接口)。裝飾者只知道其接口是什么,至于其具體類(lèi)型(是基類(lèi)還是其他派生類(lèi))只有在運(yùn)行期間才知道。
0x07.源碼中的裝飾者BufferedReader
BufferInputStream/BufferOutputStream
Spring. TransactionAwareCacheDecorator
Mybatis. Cache
0x08.源碼設(shè)計(jì)模式之裝飾著模式: https://github.com/sigmako/design-pattern/tree/master/decorator
0x09.參考慕課網(wǎng)設(shè)計(jì)模式精講: https://coding.imooc.com/class/270.html
《JAVA與模式》之裝飾模式: https://www.cnblogs.com/java-my-life/archive/2012/04/20/2455726.html
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/75335.html