1.裝飾模式的概念
動態(tài)的給一個對象添加一些額外的職責(zé)彤守,同時又不改變其結(jié)構(gòu)。使用對象的關(guān)聯(lián)關(guān)系代替繼承關(guān)系哭靖,更加靈活具垫,同時避免類型體系的快速膨脹。就增加功能來說试幽,裝飾模式比生成子類更加靈活筝蚕。
2.裝飾模式的結(jié)構(gòu)
- 抽象組件角色(Component):定義一個對象接口,可以給這些對象動態(tài)的添加職責(zé)铺坞。
- 具體組件角色(ConcreteComponent):被裝飾者起宽,定義了一個將要被裝飾增加功能的類,也可以給這個對象添加一些職責(zé)济榨。
- 抽象裝飾器(Decorator):維持一個指向構(gòu)件Component對象的實(shí)例坯沪,并定義一個與抽象組件角色Component接口一致的接口。
- 具體裝飾器角色(ConcreteDecoratorA/ConcreteDecoratorB):向組件添加職責(zé)擒滑。
3.裝飾模式的基本代碼實(shí)現(xiàn)
Component類:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public abstract class Component {
public abstract void operation();
}
ConcreteComponnet類:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("具體對象的操作");
}
}
Decorate類:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class Decorator extends Component {
protected Component component;
public void setComponent(Component component) {
this.component = component;
}
@Override
public void operation() {
if (component != null) {
component.operation();
}
}
}
ConcreteDecoratorA類:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class ConcreteDecoratorA extends Decorator {
private String addedState;
@Override
public void operation() {
// 首先運(yùn)行原Component的operation()
// 在執(zhí)行本類的功能腐晾,如addedState,相當(dāng)于對原Component進(jìn)行了裝飾
super.operation();
addedState = "New State";
System.out.println("具體裝飾對象A的操作");
}
}
ConcreteDecoratorB類:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class ConcreteDecoratorB extends Decorator {
@Override
public void operation() {
// 首先運(yùn)行原Component的operation()
// 再執(zhí)行本類的功能,如AddedBehavior(),相當(dāng)于對原Component進(jìn)行了裝飾
super.operation();
AddedBehavior();
System.out.println("具體裝飾對象B的操作");
}
// 本類特有的方法,以區(qū)分ConcreteDecoratorA
private void AddedBehavior() {
System.out.println("AddedBehavior Operation");
}
}
客戶端代碼:
package com.jxs.decorator;
/**
* Created by jiangxs on 2018/5/3.
*/
public class DecoratorClient {
public static void main(String[] args) {
ConcreteComponent concreteComponent = new ConcreteComponent();
ConcreteDecoratorA decoratorA = new ConcreteDecoratorA();
ConcreteDecoratorB decoratorB = new ConcreteDecoratorB();
// 裝飾的方法是:
// 首先用ConcreteComponent實(shí)例化對象concreteComponent
// 然后用ConcreteecoratorA的實(shí)例化對象decoratorA來包裝concreteComponent
// 再用ConcreteDecoratorB的對象decoratorB包裝decoratorA浇借,最終執(zhí)行Operation
decoratorA.setComponent(concreteComponent);
decoratorB.setComponent(decoratorA);
decoratorB.operation();
}
}
運(yùn)行結(jié)果:
具體對象的操作
具體裝飾對象A的操作
AddedBehavior Operation
具體裝飾對象B的操作
Process finished with exit code 0
4.裝飾模式的應(yīng)用
以《大話設(shè)計模式》中小菜穿衣服的搭配為例歹嘹,在這個例子中,人穿各種衣服扎阶,其中人就是ConcreteComponent,而服飾就是一個Decorator,各種具體的衣服就是ConcreteDecorator.
小菜穿衣搭配的代碼示例:
Person類(ConcreteComponent):
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*/
public class Person {
private String name;
public Person() {}
public Person(String name) {
this.name = name;
}
public void show() {
System.out.println("裝扮:"+name);
}
}
服飾類(Decorator):
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*
* 服飾類(Decorator)
*/
public class Finery extends Person {
protected Person component;
// 打扮
public void decorate(Person component) {
this.component = component;
}
@Override
public void show() {
if (component != null) {
component.show();
}
}
}
具體服飾類(ConcreteDecorator):
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*/
class TShirts extends Finery {
@Override
public void show() {
System.out.println("大T恤");
super.show();
}
}
class BigTrousers extends Finery {
@Override
public void show() {
System.out.println("垮褲");
super.show();
}
}
class Sneakers extends Finery {
@Override
public void show() {
System.out.println("破球鞋");
super.show();
}
}
class Suit extends Finery {
@Override
public void show() {
System.out.println("西裝");
super.show();
}
}
class Tie extends Finery {
@Override
public void show() {
System.out.println("領(lǐng)帶");
super.show();
}
}
class LeatherShoes extends Finery {
@Override
public void show() {
System.out.println("皮鞋");
super.show();
}
}
客戶端代碼:
package com.jxs.decoratorExample;
/**
* Created by jiangxs on 2018/5/3.
*/
public class Client {
public static void main(String[] args) {
Person xc = new Person("小菜");
System.out.println("第一種裝扮:");
Sneakers pqx = new Sneakers();
BigTrousers dkc = new BigTrousers();
TShirts tx = new TShirts();
pqx.decorate(xc);
dkc.decorate(pqx);
tx.decorate(dkc);
tx.show();
System.out.println("\n第二種裝扮");
LeatherShoes px = new LeatherShoes();
Tie ld = new Tie();
Suit xz = new Suit();
px.decorate(xc);
ld.decorate(px);
xz.decorate(ld);
xz.show();
}
}
運(yùn)行結(jié)果:
第一種裝扮:
大T恤
垮褲
破球鞋
裝扮:小菜
第二種裝扮
西裝
領(lǐng)帶
皮鞋
裝扮:小菜
Process finished with exit code 0
5.裝飾模式總結(jié)
裝飾模式是為已有功能動態(tài)地添加更多功能的一種方式潘拱。
如果當(dāng)系統(tǒng)需要新功能時,是向舊的類中添加新的代碼拧略,這些新的代碼通常裝飾了原有類的核心職責(zé)和主要行為芦岂。這種做法的問題在于:他們在主類中加入了新的字段,新的方法和新的邏輯垫蛆,從而增加了主類的復(fù)雜度禽最。而這些新加入的東西僅僅是為了滿足一些只在某種特定情況下才會執(zhí)行的特殊行為的需要腺怯。
而裝飾模式卻提供了一個非常好的解決方案,它把每個要裝飾的功能放在單獨(dú)的類中川无,并讓類包裝它所要裝飾的對象呛占,因此,當(dāng)需要執(zhí)行特殊行為時懦趋,客戶代碼就可以在運(yùn)行時根據(jù)需要有選擇地晾虑、按順序地使用裝飾功能包裝對象了。
(1)裝飾模式的優(yōu)點(diǎn):
- 把類中的裝飾功能從類中搬移去除仅叫,這樣可以簡化原有的類帜篇。
- 有效地把類的核心職責(zé)和裝飾功能區(qū)分開,而且可以去除相關(guān)類中重復(fù)的裝飾邏輯诫咱。
(2)裝飾模式的缺點(diǎn):
- 這種比繼承更加靈活機(jī)動的特性笙隙,也同時意味著更加多的復(fù)雜性。
- 裝飾模式會導(dǎo)致設(shè)計中出現(xiàn)許多小類坎缭,如果過度使用竟痰,會使程序變得很復(fù)雜。
- 裝飾模式是針對抽象組件(Component)類型編程掏呼。但是凯亮,如果你要針對具體組件編程時,就應(yīng)該重新思考你的應(yīng)用架構(gòu)哄尔,以及裝飾者是否合適假消。當(dāng)然也可以改變Component接口,增加新的公開的行為岭接,實(shí)現(xiàn)“半透明”的裝飾者模式富拗。在實(shí)際項(xiàng)目中要做出最佳選擇。
(3)適用裝飾者模式場合:
- 當(dāng)我們需要為某個現(xiàn)有的對象鸣戴,動態(tài)的增加一個新的功能或職責(zé)時啃沪,可以考慮使用裝飾模式。
- 當(dāng)某個對象的職責(zé)經(jīng)常發(fā)生變化或者經(jīng)常需要動態(tài)的增加職責(zé)窄锅,避免為了適應(yīng)這樣的變化创千,而增加繼承子類擴(kuò)展的方式,因?yàn)檫@種方式會造成子類膨脹的速度過快入偷,難以控制追驴。
注:以上代碼均可在github上進(jìn)行下載:https://github.com/xsongj/designPattern
參考:《大話設(shè)計模式》