1、裝飾模式的概念
裝飾模式就是動态地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更加靈活。
對于人來說,衣服、鞋子、領帶、襪子等都是裝飾,裝飾模式就是給光着身子的人穿上各種衣服褲子。
對于程式對象來說,每一個功能都是裝飾,給一個類增加功能,就是給這個類進行裝飾。
2、裝飾模式的UML圖及對應代碼
Compoent是一個對象接口,可以給這些對象動态地添加職責:
class interface Component{
void Operation();
}
ConcreteComponent類,定義了一個具體的對象,也可以給這個對象添加一些職責:
class ConcreteComponent implement Component{
@Override
public void Operation(){
//做一些具體的操作
}
}
Decorator 是裝飾抽象類,繼承了Component接口,從外類來擴充Component類的功能,但是對于Component來說,是無需要知道Decorator的存在的。
public class Decorator implements Component{
protected Component component;
//設定Component
public SetComponent(Component component){
this.component = component;
}
//重寫Operation(),實際執行的是Component的Operation()
@Override
public void Operation() {
if(component != null){
component.Operation();
}
}
}
ConcreteDecorator 是具體的裝飾對象,起到給Component添加職責的功能
我們來實作一下A和B
public class ConcreteDecoratorA extends Decorator {
//本類特有的功能,以差別B
private String addedState;
@Override
public void Operation() {
// 首先運作原Component的Operation()
super.sampleOperation();
// 再執行本類的功能,如addState相當于對原Component進行了裝飾
addState = "New State";
//具體裝飾對象A的操作。
}
}
public class ConcreteDecoratorB extends Decorator {
//本類特有的方法,以差別A
public AddBehavior() {
}
@Override
public void Operation() {
// 首先運作原Component的Operation()
super.sampleOperation();
// 再運作自己的功能
AddBehavior();
....
}
}
最後用戶端代碼點睛之筆:
main(){
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
ConcreteDecoratorB d2 = new ConcreteDecoratorB();
//裝飾的方法是:
//首先用 ConcreteComponent執行個體化c
//然後用 ConcreteDecoratorA的執行個體化對象d1來包裝c
//再用ConcreteDecoratorB的對象d2來包裝d1
//最後執行d2的Operation
d1.setComponent(c);
d2.setComponent(d1);
d2.Operation();
...
}
-
裝飾模式就是利用SetComponent來對對象進行包裝的。
這樣每個裝飾對象的實作就和如何使用這個對象分離開了,每個裝飾對象值關心自己的功能,不需要關心如何被添加到對象鍊當中。
注:不一定要去構造Component類,要善于變通,假如隻有一個ConcreteComponent(我們隻修飾一個“人”),那麼久沒有必要些Component類,同時,Decorator就是ConcreteComponent類的子類,如果ConcreteDecorator隻有一個(“衣服”隻有一件),那麼也沒有必要構造Decorator,直接讓唯一的ConcreteDecorator來繼承ConcreteComponent就行啦。
3、經典場景—穿衣服
在這個場景下,我們給一個人穿各種衣服,包括褲子、襪子、鞋子、衣服。
在之前的UML來說,ConcreteComponent可以說是代表着具體的一類人,而這個問題讓我們針對這個人,是以我們可以不用構造Component類,或者說 “人”這個類就是Component類。而Decorator很自然就是“服裝類”,其子類就是各種衣服,那麼我們可以畫出下面的UML圖:
接着按圖來寫代碼:
首先是Person類
class Person{
public Person(){
}
private String name;
public Person(String name){
this.name = name;
}
public abstract void show(){
System.out.plintln("穿衣服的rikka");
}
}
接着是服飾類Finery:
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
class GoldLianzi extends Finery{
@Override
public void show(){
System.out.prinlin("大金鍊子");
super.show();
}
}
class Sunglasses extends Finery{
@Override
public void show(){
System.out.prinlin("墨鏡");
super.show();
}
}
最後的用戶端代碼:
main(){
Person rikka = new Person("Rikka");
System.out.println("裝扮\n");
Sunglasses sunglasses = new Sunglasses();
GoldLianzi gold = new GoldLianzi();
Cigarette cigarette = new Cigarette();
ThugLife thuglife = new ThugLife();
sunglasses.Decorate(rikka);
gold.Decorate(sunglasses);
cigarette.Decorate(gold);
thuglife.Decorate(cigarette);
thuglife.show();
}
結果顯示:
裝扮
ThugLife帽子 香煙 大金鍊子 墨鏡 穿衣服的rikka
這樣,我們就為一個什麼都沒有穿的人,穿上了各種衣服啦!
同理就是給類加功能。
總結
學了這麼多,其實裝飾模式是為已有功能動态地添加更多功能的一種設計模式。
問題:在以往,在系統功能需要更新的時候,是向舊類添加新的代碼,這些新的代碼通常裝飾了原有類的核心職責或主要行為,但這種做法的問題就在于:它們在主類中加入了新的字段,新的方法和新的邏輯,進而增加了主類的複雜度。