裝飾模式:
以對客戶透明的方式動态地給一個對象附加上更多的責任。它是通過建立一個包裝對象,也就是裝飾來包裹真實的對象。若要擴充功能,裝飾者比繼承提供了更有彈性的替代方案。
裝飾模式的類圖如下:
在裝飾模式中的角色有:
● 抽象構件(Component)角色:給出一個抽象接口,以規範準備接收附加責任的對象。
● 具體構件(ConcreteComponent)角色:定義一個将要接收附加責任的類。
● 裝飾(Decorator)角色:持有一個構件(Component)對象的執行個體,并定義一個與抽象構件接口一緻的接口。
● 具體裝飾(ConcreteDecorator)角色:負責給構件對象“貼上”附加的責任。
源代碼:
抽象建構component:
public interface Animal {
void behavior();
}
具體建構concreteComponent:
public class Dog implements Animal {
public void behavior() {
System.out.println("小狗會跑");
}
}
裝飾者decorator:
public class Sports implements Animal {
private Animal animal;
public Sports(Animal animal){
this.animal = animal;
}
public void behavior(){
this.animal.behavior();
}
}
具體狀态 concreteDecorator:
public class Jump extends Sports {
public Jump(Animal animal) {
super(animal);
}
@Override
public void behavior() {
super.behavior();
System.out.println("會跳");
}
}
public class Sleep extends Sports{
public Sleep(Animal animal) {
super(animal);
}
public void behavior(){
super.behavior();
System.out.println("累了會睡覺");
}
}
public class Thought extends Sports{
public Thought(Animal animal) {
super(animal);
}
public void think(){
System.out.println("這是一隻會思考的動物");
}
}
測試代碼:
public class Test {
public static void main(String[] args) {
//透明的裝飾模式
Animal animal = new Dog();
animal.behavior();
System.out.println();
animal = new Jump(animal);
animal.behavior();
System.out.println();
animal = new Sleep(animal);
animal.behavior();
System.out.println();
//半透明的裝飾模式
Thought thought = new Thought(new Dog());
thought.think();
thought.behavior();
}
}
輸出結果:
小狗會跑
小狗會跑
會跳
小狗會跑
會跳
累了會睡覺
小狗會跑
這是一隻會思考的動物
可以看到我在測試代碼裡面分為了2個部分:透明的狀态模式,半透明的裝飾模式。下面就以這2個部分來介紹一下裝飾模式的使用。
我們定義了Dog類,定義了他的行為是“小狗會跑”。同時,我們又定義了一下裝飾者Jump,Sleep,通過下面這個代碼活動一個動物
Animal sleep = new Sleep(new Jump(new Dog()));
這隻動物的行為其實就是測試方法中輸出的:
小狗會跑
會跳
累了會睡覺
這就是文字開頭說的通過建立一個包裝對象,也就是裝飾來包裹真實的對象,動态地給一個對象附加上更多的責任。
這裡動态的增加的責任就是跳和睡覺。
那麼什麼是透明和半透明呢?
透明的裝飾模式:
理想的裝飾模式開頭也提到了:以對客戶透明的方式動态地給一個對象附加上更多的責任。
這裡的對客戶透明實際上就是面向接口程式設計
Animal sleep= new Sleep(new Jump(new Dog()));
還是用這個例子來說明,我們定義的是Animal,是一個接口,而不是他正在的實作Sleep類。也就是說 裝飾模式對用戶端的透明性要求程式不要聲明一個ConcreteComponent類型的變量,而應當聲明一個Component類型的變量。是以我們應該這樣寫
Animal dog = new Dog();
Animal jump = new Jump(new Dog());
而不應該這樣寫
Dog dog = new Dog();
Jump jump = new Jump(new Dog());
半透明的裝飾模式:
然而,純粹的裝飾模式很難找到。裝飾模式的用意是在不改變接口的前提下,增強所考慮的類的性能。在增強性能的時候,往往需要建立新的公開的方法。就好比我們需要的不僅僅是有行為能力的動物,還需要能思考的動物時,我們定義了一個Thought類,提供了思考的功能。那麼需要使用這個think()方法的時候,就不能通過聲明Animal接口來獲得這個功能,而是聲明Thought的引用。
//半透明的裝飾模式
Thought thought = new Thought(new Dog());
thought.think();
thought.behavior();
裝飾模式的優點
(1)裝飾模式與繼承關系的目的都是要擴充對象的功能,但是裝飾模式可以提供比繼承更多的靈活性。裝飾模式允許系統動态決定“貼上”一個需要的“裝飾”,或者除掉一個不需要的“裝飾”。繼承關系則不同,繼承關系是靜态的,它在系統運作前就決定了。
(2)通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。
裝飾模式的缺點
由于使用裝飾模式,可以比使用繼承關系需要較少數目的類。使用較少的類,當然使設計比較易于進行。但是,在另一方面,使用裝飾模式會産生比使用繼承關系更多的對象。更多的對象會使得查錯變得困難,特别是這些對象看上去都很相像。