舉個慄子 問題描述 可以給人搭配嘻哈服或白領裝的程式。 簡單實現 代碼 測試結果 存在缺陷 如果需要增加“超人”裝扮,會導致需要修改“Person”類,違背了 開放 封閉原則 簡單實現進化版 代碼 測試結果 存在問題 現在如果要加超人裝扮,只要增加子類就可以了,但是這麼做雖然把“服裝”類和“人”類分 ...
舉個慄子
問題描述
可以給人搭配嘻哈服或白領裝的程式。
簡單實現
代碼
/**
* 人類
* Created by callmeDevil on 2019/6/23.
*/
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void wearTShirts(){
System.out.print("大T恤 ");
}
public void wearBigTrouser(){
System.out.print("垮褲 ");
}
public void wearSneakers(){
System.out.print("破球鞋 ");
}
public void wearSuit(){
System.out.print("西裝 ");
}
public void wearTie(){
System.out.print("領帶 ");
}
public void wearLeatherShoes(){
System.out.print("皮鞋 ");
}
public void show(){
System.out.println("裝扮的" + name);
}
}
/**
* 裝扮測試類
* Created by callmeDevil on 2019/6/23.
*/
public class Test {
public static void main(String[] args) {
Person devil = new Person("Devil");
System.out.println("第一種裝扮:");
devil.wearTShirts();
devil.wearBigTrouser();
devil.wearSneakers();
devil.show();
System.out.println("\n第二種裝扮:");
devil.wearSuit();
devil.wearTie();
devil.wearLeatherShoes();
devil.show();
}
}
測試結果
第一種裝扮:
大T恤 垮褲 破球鞋 裝扮的Devil
第二種裝扮:
西裝 領帶 皮鞋 裝扮的Devil
存在缺陷
如果需要增加“超人”裝扮,會導致需要修改“Person”類,違背了開放-封閉原則
簡單實現進化版
代碼
/**
* 人類
* Created by callmeDevil on 2019/6/23.
*/
public class Person {
private String name;
public Person(String name){
this.name = name;
}
public void show(){
System.out.print("裝扮的" + name);
}
}
/**
* 服裝抽象類
* Created by callmeDevil on 2019/6/23.
*/
public abstract class Finery {
public abstract void show();
}
/**
* T恤 類
* Created by callmeDevil on 2019/6/23.
*/
public class TShirts extends Finery {
@Override
public void show() {
System.out.print("大T恤 ");
}
}
/**
* 垮褲 類
* Created by callmeDevil on 2019/6/23.
*/
public class BigTrouser extends Finery {
@Override
public void show() {
System.out.print("垮褲 ");
}
}
// 其餘子類相似,此處省略
/**
* 裝飾升級版測試
* Created by callmeDevil on 2019/6/23.
*/
public class Test {
public static void main(String[] args) {
Person devil = new Person("Devil");
System.out.println("第一種裝扮:");
Finery tShirts = new TShirts();
Finery bigTrouser = new BigTrouser();
Finery sneakers = new Sneakers();
tShirts.show();
bigTrouser.show();
sneakers.show();
devil.show();
System.out.println("\n第二種裝扮:");
Finery suit = new Suit();
Finery tie = new Tie();
Finery leatherShoes = new LeatherShoes();
suit.show();
tie.show();
leatherShoes.show();
devil.show();
}
}
測試結果
第一種裝扮:
大T恤 垮褲 破球鞋 裝扮的Devil
第二種裝扮:
西裝 領帶 皮鞋 裝扮的Devil
存在問題
現在如果要加超人裝扮,只要增加子類就可以了,但是這麼做雖然把“服裝”類和“人”類分離開了,仍然是存在問題的。把“大T恤”、“垮褲”、“破球鞋”和“裝扮的Devil”一個詞一個詞顯示出來,就好比:你光著身子,當著大家的面,先穿T恤,再穿褲子,再穿鞋,仿佛在跳穿衣舞。。。因此需要一個房間(組合類)來換衣服,同時這個穿的順序對每個人來說是不固定的,有的人喜歡先穿褲子,再穿鞋,最後穿T恤。。只需要把所需的功能按正確的順序串聯起來進行控制即可。
裝飾模式
定義
動態地給一個對象添加一些額外的職責,就增加來說,裝飾模式比生成子類更為靈活
UML圖
- Component是定義一個對象介面,可以給這些對象動態地添加職責。
- ConcreteComponent是定義了一個具體的對象,也可以給這個對象添加一些職責。
- Decorator,裝飾抽象類,繼承了Component,從外類來擴展Component類功能,但對於Component來說,是無需知道Decorator的存在的。
- 至於ConcreteDecorator就是具體的裝飾對象,起到了給Component添加職責的功能。
簡單實現究極進化->裝飾模式實現
代碼
/**
* 究極進化人類(ConcreteComponent)
* Created by callmeDevil on 2019/6/23.
*/
public class Person {
private String name;
public Person(){}
public Person(String name){
this.name = name;
}
public void show(){
System.out.println("裝扮的" + name);
}
}
/**
* 究極進化 服飾類(Decorator)
* Created by callmeDevil on 2019/6/23.
*/
public abstract class Finery extends Person{
protected Person component;
/**
* 裝扮
* @param component
*/
public void decorate(Person component) {
this.component = component;
}
@Override
public void show() {
if (component != null) {
component.show();
}
}
}
/**
* 究極進化 T恤(ConcreteDecorator)
* Created by callmeDevil on 2019/6/23.
*/
public class TShirts extends Finery{
@Override
public void show() {
System.out.print("大T恤 ");
super.show();
}
}
/**
* 究極進化 垮褲(ConcreteDecorator)
* Created by callmeDevil on 2019/6/23.
*/
public class BigTrouser extends Finery {
@Override
public void show() {
System.out.print("垮褲 ");
super.show();
}
}
// 其餘子類相似,此處省略
/**
* 裝飾模式測試
* Created by callmeDevil on 2019/6/23.
*/
public class Test {
public static void main(String[] args) {
Person devil = new Person("Devil");
System.out.println("第一種裝扮:");
Sneakers sneakers = new Sneakers();
BigTrouser bigTrouser = new BigTrouser();
TShirts tShirts = new TShirts();
// 裝飾
sneakers.decorate(devil);
bigTrouser.decorate(sneakers);
tShirts.decorate(bigTrouser);
tShirts.show();
System.out.println("\n第二種裝扮:");
LeatherShoes leatherShoes = new LeatherShoes();
Tie tie = new Tie();
Suit suit = new Suit();
// 裝飾
leatherShoes.decorate(devil);
tie.decorate(leatherShoes);
suit.decorate(tie);
suit.show();
}
}
測試結果
第一種裝扮:
大T恤 垮褲 破球鞋 裝扮的Devil
第二種裝扮:
西裝 領帶 皮鞋 裝扮的Devil
總結
- 裝飾模式是利用setComponent來對對象進行包裝的,這樣每個裝飾對象的實現就和如何使用這個對象分離開了,每個裝飾對象只關心自己的功能,不需要關心如何被添加到對象鏈當中。
- 如果只有一個ConcreteComponent類而沒有抽象的Component類,那麼Decorator類可以是ConcreteComponent的一個子類。同樣道理,如果只有一個ConcreteDecorator類,那麼就沒有必要建立一個單獨的Decorator類,而可以把Decorator和ConcreteDecorator的責任合併成一個類。
- 裝飾模式是為已有功能動態地添加更多功能的一種方式。
- 不使用裝飾模式,且系統需要新功能的時候,是向舊的類中添加新的代碼,這些新加的代碼通常裝飾了原有類的核心職責或主要行為。在主類中加入了新的欄位、方法和邏輯,會增加主類的複雜度,而這些新加入的東西僅僅是為了滿足一些只在某種特定情況下才會執行的特殊需求。裝飾模式提供了非常好的解決方案,它把每個要裝飾的功能放在單獨的類中,並讓這個類包裝它所要裝飾的對象,因此,當需要執行特殊行為時,客戶代碼就可以在運行時根據需要有選擇地、按順序地使用裝飾功能包裝對象。
- 裝飾模式的優點是把類中裝飾功能從類中搬移去除,這樣可以簡化原有的類。這麼做最大的好處就是有效地把類的核心職責和裝飾功能區分開了,而且可以去除相關類中重覆的裝飾邏輯。