1. 前文彙總
2. 小明起牀記
小明每天早晨都是起牀困難大戶,大冬天的太冷了,溫暖的被窩緊緊的拉住小明,阻止小明每天早晨的起牀。
鬧鐘響了一遍又一遍,如果再不起牀就要遲到了,遲到了就要扣錢,扣了錢就要喝西北風了。
每天早晨督促小明起牀的根本不是鬧鐘,而是貧窮。
起牀第一件事兒是穿衣服,先傳衣服,再傳褲子,然後穿鞋子,最後穿上一件外套,出門上班。
首先,定義一個抽象的小明,小明是個人,所以定義一個人:
public abstract class Person {
abstract void dress();
}
每個人早晨起牀都要穿衣服,這裏定義一個穿衣服的方法。
具體的小明上線:
public class Man extends Person {
@Override
void dress() {
System.out.println("先穿衣服");
}
}
接下來我們要定義一個抽象的裝飾器了,小明要穿的是衣服,我們將衣服抽象成一個類:
public abstract class Clothes extends Person {
private Person person;
public Clothes(Person person) {
this.person = person;
}
@Override
void dress() {
this.person.dress();
}
}
接下來是具體的衣服:
public class Trousers extends Clothes {
public Trousers(Person person) {
super(person);
}
@Override
void dress() {
super.dress();
this.dressTrousers();
}
private void dressTrousers() {
System.out.println("穿上褲子啦!!!");
}
}
public class Shoes extends Clothes {
public Shoes(Person person) {
super(person);
}
@Override
void dress() {
super.dress();
this.dressShoes();
}
private void dressShoes() {
System.out.println("穿上鞋子啦!!!");
}
}
public class Coat extends Clothes {
public Coat(Person person) {
super(person);
}
@Override
void dress() {
super.dress();
this.dressCoat();
}
private void dressCoat() {
System.out.println("穿上外套啦!!!");
}
}
最後是一個測試類:
public class Test1 {
public static void main(String[] args) {
Person person = new Man();
person.dress();
System.out.println("--------------");
System.out.println("增加褲子適配器");
person = new Trousers(person);
person.dress();
System.out.println("--------------");
System.out.println("增加鞋子適配器");
person = new Shoes(person);
person.dress();
System.out.println("--------------");
System.out.println("增加外套適配器");
person = new Coat(person);
person.dress();
}
}
測試結果如下:
先穿衣服
--------------
增加褲子適配器
先穿衣服
穿上褲子啦!!!
--------------
增加鞋子適配器
先穿衣服
穿上褲子啦!!!
穿上鞋子啦!!!
--------------
增加外套適配器
先穿衣服
穿上褲子啦!!!
穿上鞋子啦!!!
穿上外套啦!!!
上面這麼寫有點麻煩,我們可以稍微縮減一下測試類,使用裝飾器嵌套,一次性直接把所有的衣服都穿好:
public class Test2 {
public static void main(String[] args) {
Person person = new Coat(new Shoes(new Trousers(new Man())));
person.dress();
}
}
3. 裝飾器模式
3.1 定義
裝飾模式(Decorator Pattern)是一種比較常見的模式,其定義如下:
Attachadditional responsibilities to an object dynamically keeping the sameinterface.Decorators provide a flexible alternative to subclassing forextending functionality.(動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾模式相比生成子類更爲靈活。)
- Component: 抽象構件,是一個接口或者是抽象類,就是定義我們最核心的對象,也就是最原始的對象。
- ConcreteComponent: 具體構件,是最核心、最原始、最基本的接口或抽象類的實現。
- Decorator: 通用的裝飾 ConcreteComponent 的裝飾器,其內部必然有一個屬性指向 Component 抽象組件;其實現一般是一個抽象類,主要是爲了讓其子類按照其構造形式傳入一個 Component 抽象組件,這是強制的通用行爲(當然,如果系統中裝飾邏輯單一,並不需要實現許多裝飾器,那麼我們可以直接省略該類,而直接實現一個 具體裝飾器(ConcreteDecorator) 即可)。
- ConcreteDecorator: Decorator 的具體實現類,理論上,每個 ConcreteDecorator 都擴展了 Component 對象的一種功能。
通用代碼:
public abstract class Component {
abstract void operate();
}
public class ConcreteComponent extends Component {
@Override
void operate() {
System.out.println("do Something");
}
}
public abstract class Decorator extends Component {
private Component component = null;
// 通過構造函數傳遞被修飾者
public Decorator(Component component) {
this.component = component;
}
// 委託給被修飾者執行
@Override
void operate() {
this.component.operate();
}
}
public class ConcreteDecorator1 extends Decorator {
// 定義被修飾者
public ConcreteDecorator1(Component component) {
super(component);
}
private void method1() {
System.out.println("method1 修飾");
}
@Override
void operate() {
this.method1();
super.operate();
}
}
public class ConcreteDecorator2 extends Decorator {
public ConcreteDecorator2(Component component) {
super(component);
}
private void method2() {
System.out.println("method2 修飾");
}
@Override
void operate() {
super.operate();
this.method2();
}
}
public class Test {
public static void main(String[] args) {
Component component = new ConcreteComponent();
// 第一次修飾
component = new ConcreteDecorator1(component);
// 第二次修飾
component = new ConcreteDecorator2(component);
// 修飾後運行
component.operate();
}
}
3.2 優點
裝飾類和被裝飾類可以獨立發展,而不會相互耦合。換句話說, Component 類無須知道 Decorator 類, Decorator 類是從外部來擴展 Component 類的功能,而 Decorator 也不用知道具體的構件。
3.3 缺點
對於裝飾模式記住一點就足夠了:多層的裝飾是比較複雜的。爲什麼會複雜呢?想想看,就像剝洋蔥一樣,至於剝到了最後才發現是最裏層的裝飾出現了問題,想象一下工作量吧,因此,儘量減少裝飾類的數量,以便降低系統的複雜度。
3.3 使用場景
- 需要擴展一個類的功能,或給一個類增加附加功能。
- 需要動態地給一個對象增加功能,這些功能可以再動態地撤銷。
- 需要爲一批的兄弟類進行改裝或加裝功能,當然是首選裝飾模式。