1.定義
動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來說,裝飾模式相比生成子類更為靈活。
也叫裝飾者模式或者裝飾器模式。
比如給一個(gè)人穿衣服裝飾。
抽象一個(gè)人,給他穿的動(dòng)作。普通方式要再裝飾他就需要繼承它,然后做修改,但是會(huì)對(duì)孫子類有影響。
現(xiàn)在是繼承這個(gè)抽象的人,然后再穿的動(dòng)作之后進(jìn)行其他裝飾。
2.角色
- Component:定義一個(gè)對(duì)象接口,可以給這些對(duì)象動(dòng)態(tài)添加職責(zé)。真實(shí)對(duì)象和裝飾者對(duì)象有相同的接口,這樣客戶端不用知道內(nèi)部有裝飾者對(duì)象(Decorator)
存在的,還是以之前處理真實(shí)對(duì)象的相同方式來和裝飾者對(duì)象交互。
ConcreteComponent:是定義了一個(gè)具體的對(duì)象(例如:人),也可以給這個(gè)對(duì)象添加一些其他職責(zé)。
Decorator:裝飾抽象類,繼承了Component,從外類來擴(kuò)展Component類的功能,但對(duì)Component來說,是無需知道Decorator存在的。
ConcreteDecorator:就是具體的裝飾對(duì)象了(衣服,鞋子..),它起到了給Component添加職責(zé)的功能。
3.代碼實(shí)現(xiàn)
Component對(duì)象接口(ICar),汽車移動(dòng)
/**
* ICar表示Component:
*/
public interface ICar {
void move();//汽車移動(dòng)
}
具體真實(shí)的對(duì)象ConcreteComponent:這里是Car,就是具體的汽車,未裝飾的汽車
//ConcreteComponent:具體的對(duì)象
class Car implements ICar{
@Override
public void move() {
System.out.println("汽車移動(dòng)");
}
}
裝飾抽象類Decorator:SuperCar這里需要持有一個(gè)真實(shí)對(duì)象的引用,也就是Car對(duì)象
//Decorator:裝飾抽象類
class SuperCar implements ICar{
protected ICar car;//持有一個(gè)真實(shí)對(duì)象的引用
@Override
public void move() {
car.move();//這里調(diào)用真實(shí)對(duì)象的移動(dòng)方法
}
//構(gòu)造的時(shí)候傳參
public SuperCar(ICar car) {
super();
this.car = car;
}
}
實(shí)現(xiàn)具體的裝飾對(duì)象ConcreteDecorator
//ConcreteDecorator:就是具體的裝飾對(duì)象
class FlayCar extends SuperCar {
public FlayCar(ICar car) {
super(car);
}
//這里就是新增的功能
public void flay(){
System.out.println("---天上飛");
}
@Override
public void move() {
super.move();
flay();//在原有移動(dòng)的基礎(chǔ)上,裝飾了一個(gè)fly的功能
}
}
//ConcreteDecorator:就是具體的裝飾對(duì)象
class WaterCar extends SuperCar {
public WaterCar(ICar car) {
super(car);
}
//這里就是新增的功能
public void swim(){
System.out.println("---水里游");
}
@Override
public void move() {
super.move();
swim();//在原有移動(dòng)的基礎(chǔ)上,裝飾了一個(gè)swim的功能
}
}
客戶端
public static void main(String[] args) {
Car car = new Car();
car.move();//這里打印未增加新功能的時(shí)候:汽車移動(dòng)
System.out.println("--------增加飛行功能-------");
FlayCar flyCar = new FlayCar(car);//將真實(shí)對(duì)象傳入裝飾對(duì)象中
flyCar.move();//這里就是增加了飛行后的裝飾
System.out.println("--------增加潛水功能-------");
WaterCar waterCar = new WaterCar(car);//將真實(shí)對(duì)象傳入裝飾對(duì)象中
waterCar.move();//這里就是增加了潛水功能后的裝飾
}
打印結(jié)果
汽車移動(dòng)
--------增加飛行功能-------
汽車移動(dòng)
---天上飛
--------增加潛水功能-------
汽車移動(dòng)
---水里游
4.總結(jié)
裝飾模式(Decorator)也叫包裝器模式(Wrapper)
裝飾模式降低系統(tǒng)的耦合度,可以動(dòng)態(tài)的增加或刪除對(duì)象的職責(zé),并使得需要裝飾的具體構(gòu)建類和具體裝飾類可以獨(dú)立變化,以便增加新的具體構(gòu)建類和具體裝飾類。
優(yōu)點(diǎn):
擴(kuò)展功能強(qiáng),相比繼承來說更靈活。繼承的話會(huì)導(dǎo)致子類個(gè)數(shù)增加。而裝飾者模式不會(huì)出現(xiàn)這種情況。
可以對(duì)一個(gè)對(duì)象進(jìn)行多次裝飾,創(chuàng)造出不同行為的組合,得到功能更加強(qiáng)大的對(duì)象。
具體構(gòu)建類和具體裝飾類可以獨(dú)立變化,用戶可以根據(jù)需要自己增加新的構(gòu)件子類和具體裝飾類。
缺點(diǎn):
產(chǎn)生很多小對(duì)象,大量小對(duì)象會(huì)占據(jù)內(nèi)存。一定程度上影響了性能。
裝飾模式易于出錯(cuò),調(diào)試排查比較麻煩。
應(yīng)用的場(chǎng)景:
IO中輸入流和輸出流
Swing包中圖形界面構(gòu)件功能
Servlet API中提供了一個(gè)request對(duì)象的Decorator設(shè)計(jì)模式的默認(rèn)實(shí)現(xiàn)類HttpServletRequestWrapper,增強(qiáng)了request對(duì)象的功能。
Struts2中,request,response,session對(duì)象的處理。
裝飾模式和橋接模式的區(qū)別:
兩個(gè)模式都是為了解決過多子類對(duì)象的問題,橋接模式是對(duì)象自身有過多的維度,造成過多的子類。而讓維度分類后在搭建一個(gè)橋梁來聯(lián)系起來。
而裝飾模式是解決在增加新功能的時(shí)候產(chǎn)生多個(gè)類的問題。
Android
android中Context和ContextImpl