二十、裝飾設計模式
阿新 • • 發佈:2019-01-07
1. 裝飾設計模式介紹
定義
動態地給一個物件新增一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。
2. 裝飾設計模式使用場景
動態地給一個物件新增一些額外的職責。
3. 裝飾設計模式UML類圖
角色介紹:
- Component:抽象元件,充當的是被裝飾的原始物件。
- ConcreteComponent:元件具體實現類。
- Decotor:抽象裝飾類:職責就是為了裝飾元件物件,內部有一個指向元件物件的引用。
- ConcreteDecoratorA:裝飾者的具體實現類
- Client:測試類
4. 裝飾設計模式簡單實現
- (1)、首先定義一個抽象元件類:
public abstract class Component {
/**
* 抽象的方法
*/
public abstract void operation();
}
抽象元件類裡面只有一個抽象方法operation()
- (2)、元件具體實現類:
public class ConcreteComponent extends Component {
@Override
public void operation() {
}
}
元件具體實現類繼承自組建抽象類,在operation方法裡面有具體的實現邏輯。
- (3)、抽象裝飾者:
public class Decorator extends Component {
private Component component;//持有一個component物件的引用
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
抽象裝飾者類也繼承自Component類,在建構函式裡面接收一個Component型別的Component物件的引用,在operation()方法裡面呼叫component的operation方法。
- (4)、裝飾者實現類:
ConcreteDecoratorA 和 ConcreteDecoratorB只是operation方法呼叫父類operation方法的順便不同而已。
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
opetateA();
super.operation();
opetateB();
}
private void opetateB() {
}
private void opetateA() {
}
}
裝飾者實現類裡面,繼承自Decorator類,在operation方法裡面會呼叫父類operation方法,也可以自己進行相關邏輯操作。
- (5)測試類:
public class Client {
public static void main(String[] args) {
//構造被裝飾的元件物件
ConcreteComponent concreteComponent = new ConcreteComponent();
//構造裝飾者物件A,並呼叫
ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(concreteComponent);
concreteDecoratorA.operation();
System.out.println("----");
//構造裝飾者物件B,並呼叫
ConcreteDecoratorA concreteDecoratorB = new ConcreteDecoratorA(concreteComponent);
concreteDecoratorB.operation();
}
}
為了讓大家更好的理解裝飾者設計模式,現在有如下場景:
比如我們現在要去買一份炒飯,如果什麼都不加的話,只要五元;加青椒的話,多收五元;加肉絲的話多收三元。
- (1)、米飯基類:
public abstract class Rice {
private String name;
public String getName() {
return name;
}
public abstract int getPrice();
}
米飯基類裡面有一個名稱和一個價格:
- (2)、炒飯基類:
public class FryRice extends Rice {
public FryRice() {
}
@Override
public String getName() {
return "炒飯";
}
@Override
public int getPrice() {
return 5;
}
}
炒飯返回的價格是5元
- (3)、配料類,相當於上面的裝飾類
public class Ingredient extends Rice {
private Rice rice;
public Ingredient(Rice rice) {
this.rice = rice;
}
@Override
public String getName() {
return rice.getName();
}
@Override
public int getPrice() {
return rice.getPrice();
}
}
- (4)、火腿配料
public class Ham extends Ingredient {
public Ham(Rice rice) {
super(rice);
}
@Override
public String getName() {
return super.getName() + ",加火腿";
}
@Override
public int getPrice() {
return super.getPrice() + 3;
}
}
- (5)、瘦肉配料:
public class Lean extends Ingredient {
public Lean(Rice rice) {
super(rice);
}
@Override
public String getName() {
return super.getName() + ",加瘦肉";
}
@Override
public int getPrice() {
return super.getPrice() + 4;
}
}
- (6)、測試類:
public class Client {
public static void main(String[] args) {
//炒飯基類
FryRice fryRice = new FryRice();
System.out.println(fryRice.getName() + "," + fryRice.getPrice());
//瘦肉炒飯基類
Lean leanFryRice = new Lean(fryRice);
System.out.println(leanFryRice.getName() + "," + leanFryRice.getPrice());
//瘦肉火腿炒飯
Ham ham = new Ham(leanFryRice);
System.out.println(ham.getName() + "," + ham.getPrice());
}
}
測試結果如下:
炒飯,5
炒飯,加瘦肉,9
炒飯,加瘦肉,加火腿,12
5. 裝飾設計模式在Android原始碼中
在Android中,我們會經常在Activity裡面使用startActivity()方法啟動一個元件。
startActivity這個方法最開始在Context中定義,Context是一個抽象類,裡面定義了許多抽象方法。Context相當於裝飾設計模式裡面的抽象元件。
startActivity具體實現在ContextImpl中完成的。ContextImpl相當於元件的具體實現。
Activity繼承自ContextThemeWrapper,ContextWrapper又繼承自Context。
在ContextWrapper裡面有如下程式碼:
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
可見這裡的ContextWrapper就是我們裝飾者。
最後給一下幾個類的關係:
6. 總結
- 優點:
- 裝飾模式與繼承關係的目的都是要擴充套件物件的功能,但是裝飾模式可以提供比繼承更多的靈活性。繼承關係是靜態,在系統執行前就決定了;裝飾設計模式允許動態決定新增或者刪除這些“裝飾”。
- 通過不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合。
- 缺點:
- 產生多餘的類。