設計模式之裝飾(Decorator)模式
設計模式之裝飾(Decorator)模式
(一)什麽是裝飾(Decorator)模式
裝飾模式,又稱為包裝模式,它以對客戶端透明的方式擴張對象的功能,是繼承關系的替代方案之一。
裝飾模式可以在不使用創造更多子類的情況下,將對象的功能加以擴展。
(二)裝飾模式的角色
1)抽象構件(Component)角色:給出一個抽象接口,以規範準備接受附加責任的對象
2)具體構件(Concrete component)角色:定義一個將要接受附加責任的類
3)裝飾角色(Decorator)角色:持有一個構建(Component)對象的實例
4)具體裝飾(Concrete decorator)角色:負責給構件對象添加功能。
(三)裝飾模式的實現
想象一下這樣一種情況,定義了一個接口Car(代碼如下),裏邊只包含一個方法move(),這個方法用來展示具體車的移動方式。
public interface Car {
void move();
}
首先我們創建一個最普通的車RunCar(這裏的普通指的是移動方式為陸地移動),實現這個接口。
public class RunCar implements Car {
@Override
public void move() {
this.run();
}
public void run() {
System.out.println("可以跑");
}
}
隨著科技的進步,可能會有能夠飛的車FlyCar,可能會有SwimCar,我們首先想到的實現方式就是繼承,通過子類的實現擴展父類的功能,在這裏指的是分別創建FlyCar類和SwimCar類實現Car接口。如果有這樣一種需求,創建一種既能飛fly也能swim的FlySwimCar,這樣該如何實現的,傳統的繼承能夠實現,但一方面java只支持單繼承,靈活性較差,另一方面,之前已經分別創建了FlyCar和SwimCar,如果再創建FlySwimCar會造成代碼重復,想象一下,如果能夠在FlyCar的基礎上擴展swim功能就好了。
恰巧,裝飾著模式就能解決此類問題。
這裏我們的Component角色 指的就是Car接口,它既是被裝飾類的父接口,也是裝飾類的父接口。
RunCar扮演的就是被裝飾者的角色,它是Component角色的實現類。
抽象裝飾角色為CarDecorator,實現了Car接口,切內部包含一個Car的引用,用來保存被裝飾的對象:
public abstract class CarDecorator implements Car {
private Car car;
public CarDecorator(Car car) {
this.car = car;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public abstract void move();
}
具體抽象角色用於具體功能的擴展,在這裏SwimCarDecorator為傳進的汽車對象增加swim功能,FlyCarDecorator為傳進的汽車對象增加fly功能。
public class SwimCarDecorator extends CarDecorator {
public SwimCarDecorator(Car car) {
super(car);
}
public void move() {
this.getCar().move();
this.swim();
}
public void swim() {
System.out.println("可以遊");
}
}
public class FlyCarDecorator extends CarDecorator {
public FlyCarDecorator(Car car) {
super(car);
}
@Override
public void move() {
this.getCar().move();
this.fly();
}
public void fly() {
System.out.println("可以飛");
}
}
這樣以來,如果要創建一個會飛的汽車,那麽把一個普通汽車傳給FlyCarDecorator即可,如果創建一個會swim的車,把普通汽車傳給SwimDecorator即可,如果想創建一個既會fly也會swim,只需把一個普通對的車傳給FlyCarDecorator,再傳給SwimDecorator即可。
public class Client {
public static void main(String[] args) {
Car runCar = new RunCar();
runCar.move();
System.out.println("-----------");
Car flyCar = new FlyCarDecorator(runCar);
flyCar.move();
System.out.println("-----------");
Car flySwimCar = new SwimCarDecorator(new FlyCarDecorator(new RunCar()));
flySwimCar.move();
}
}
(四)在什麽情況下使用裝飾模式
需要擴展一個類的功能,或給一個類增加附加責任。
需要動態地給一個對象增加功能,這些功能可以動態的撤銷
需要增加由一些基本功能排列則和而產生的非常大量的功能,從而使繼承關系變得不顯示。
(五)裝飾模式的簡化
1)如果只有一個ConcreteComponent類而沒有抽象的Component接口,可以把Decorator類設為ConcreteComponent的一個子類
2)如果只有一個ConcreteDecorator類,就沒有必要定義Decorator類
(六)裝飾模式的優缺點
優點:
1)裝飾模式與繼承關系的目的都是擴展對象的功能,裝飾模式可以提供比繼承更多的靈活性。繼承是靜態的,而裝飾是動態的。
2)通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可是設計出很多不同行為的組合。
缺點:
使用裝飾比使用繼承需要更少數目的類,使用較少的類當然設計比較易於進行,但另一方面,裝飾模式會產生比繼承關系更多的對象,這些對象看上去都很相似,因此查錯更為困難。
設計模式之裝飾(Decorator)模式