装饰模式(装饰设计模式)详解——小马同学@Tian
裝飾模式(裝飾設計模式)詳解
上班族大多都有睡懶覺的習慣,每天早上上班時間都很緊張,于是很多人為了多睡一會,就會用方便的方式解決早餐問題。有些人早餐可能會吃煎餅,煎餅中可以加雞蛋,也可以加香腸,但是不管怎么“加碼”,都還是一個煎餅。在現實生活中,常常需要對現有產品增加新的功能或美化其外觀,如房子裝修、相片加相框等,都是裝飾器模式。
在軟件開發過程中,有時想用一些現存的組件。這些組件可能只是完成了一些核心功能。但在不改變其結構的情況下,可以動態地擴展其功能。所有這些都可以釆用裝飾模式來實現。
裝飾模式的定義與特點
裝飾(Decorator)模式的定義:指在不改變現有對象結構的情況下,動態地給該對象增加一些職責(即增加其額外功能)的模式,它屬于對象結構型模式。
裝飾(Decorator)模式的主要優點有:
- 裝飾器是繼承的有力補充,比繼承靈活,在不改變原有對象的情況下,動態的給一個對象擴展功能,即插即用
- 通過使用不用裝飾類及這些裝飾類的排列組合,可以實現不同效果
- 裝飾器模式完全遵守開閉原則
其主要缺點是:
? 裝飾模式會增加許多子類,過度使用會增加程序得復雜性。
裝飾模式的結構與實現
通常情況下,擴展一個類的功能會使用繼承方式來實現。但繼承具有靜態特征,耦合度高,并且隨著擴展功能的增多,子類會很膨脹。如果使用組合關系來創建一個包裝對象(即裝飾對象)來包裹真實對象,并在保持真實對象的類結構不變的前提下,為其提供額外的功能,這就是裝飾模式的目標。下面來分析其基本結構和實現方法。
1. 模式的結構
裝飾模式主要包含以下角色。
裝飾模式的結構圖如圖 1 所示。
圖1 裝飾模式的結構圖
2. 模式的實現
裝飾模式的實現代碼如下:
package decorator;public class DecoratorPattern {public static void main(String[] args) {Component p = new ConcreteComponent();p.operation();System.out.println("---------------------------------");Component d = new ConcreteDecorator(p);d.operation();} }//抽象構件角色 interface Component {public void operation(); }//具體構件角色 class ConcreteComponent implements Component {public ConcreteComponent() {System.out.println("創建具體構件角色");}public void operation() {System.out.println("調用具體構件角色的方法operation()");} }//抽象裝飾角色 class Decorator implements Component {private Component component;public Decorator(Component component) {this.component = component;}public void operation() {component.operation();} }//具體裝飾角色 class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}public void operation() {super.operation();addedFunction();}public void addedFunction() {System.out.println("為具體構件角色增加額外的功能addedFunction()");} }程序運行結果如下:
創建具體構件角色 調用具體構件角色的方法operation() --------------------------------- 調用具體構件角色的方法operation() 為具體構件角色增加額外的功能addedFunction()裝飾模式的應用實例
【例1】用裝飾模式實現游戲角色“莫莉卡·安斯蘭”的變身。
分析:在《惡魔戰士》中,游戲角色“莫莉卡·安斯蘭”的原身是一個可愛少女,但當她變身時,會變成頭頂及背部延伸出蝙蝠狀飛翼的女妖,當然她還可以變為穿著漂亮外衣的少女。這些都可用裝飾模式來實現,在本實例中的“莫莉卡”原身有 setImage(String t) 方法決定其顯示方式,而其 變身“蝙蝠狀女妖”和“著裝少女”可以用 setChanger() 方法來改變其外觀,原身與變身后的效果用 display() 方法來顯示,圖 2 所示是其結構圖。
圖2 游戲角色“莫莉卡·安斯蘭”的結構圖
程序代碼如下:
package decorator;import java.awt.*; import javax.swing.*;public class MorriganAensland {public static void main(String[] args) {Morrigan m0 = new original();m0.display();Morrigan m1 = new Succubus(m0);m1.display();Morrigan m2 = new Girl(m0);m2.display();} }//抽象構件角色:莫莉卡 interface Morrigan {public void display(); }//具體構件角色:原身 class original extends JFrame implements Morrigan {private static final long serialVersionUID = 1L;private String t = "Morrigan0.jpg";public original() {super("《惡魔戰士》中的莫莉卡·安斯蘭");}public void setImage(String t) {this.t = t;}public void display() {this.setLayout(new FlowLayout());JLabel l1 = new JLabel(new ImageIcon("src/decorator/" + t));this.add(l1);this.pack();this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setVisible(true);} }//抽象裝飾角色:變形 class Changer implements Morrigan {Morrigan m;public Changer(Morrigan m) {this.m = m;}public void display() {m.display();} }//具體裝飾角色:女妖class Succubus extends Changer {public Succubus(Morrigan m) {super(m);}public void display() {setChanger();super.display();}public void setChanger() {((original) super.m).setImage("Morrigan1.jpg");} }//具體裝飾角色:少女 class Girl extends Changer {public Girl(Morrigan m) {super(m);}public void display() {setChanger();super.display();}public void setChanger() {((original) super.m).setImage("Morrigan2.jpg");} }程序運行結果如圖 3 所示。
圖3 游戲角色“莫莉卡·安斯蘭”的變身
裝飾模式的應用場景
前面講解了關于裝飾模式的結構與特點,下面介紹其適用的應用場景,裝飾模式通常在以下幾種情況使用。
- 當需要給一個現有類添加附加職責,而又不能采用生成子類的方法進行擴充時。例如,該類被隱藏或者該類是終極類或者采用繼承方式會產生大量的子類。
- 當需要通過對現有的一組基本功能進行排列組合而產生非常多的功能時,采用繼承關系很難實現,而采用裝飾模式卻很好實現。
- 當對象的功能要求可以動態地添加,也可以再動態地撤銷時。
裝飾模式在 Java 語言中的最著名的應用莫過于 Java I/O 標準庫的設計了。例如,InputStream 的子類 FilterInputStream,OutputStream 的子類 FilterOutputStream,Reader 的子類 BufferedReader 以及 FilterReader,還有 Writer 的子類 BufferedWriter、FilterWriter 以及 PrintWriter 等,它們都是抽象裝飾類。
下面代碼是為 FileReader 增加緩沖區而采用的裝飾類 BufferedReader 的例子:
BufferedReader in=new BufferedReader(new FileReader("filename.txtn));String s=in.readLine();裝飾模式的擴展
裝飾模式所包含的 4 個角色不是任何時候都要存在的,在有些應用環境下模式是可以簡化的,如以下兩種情況。
(1) 如果只有一個具體構件而沒有抽象構件時,可以讓抽象裝飾繼承具體構件,其結構圖如圖 4 所示。
圖4 只有一個具體構件的裝飾模式
(2) 如果只有一個具體裝飾時,可以將抽象裝飾和具體裝飾合并,其結構圖如圖 5 所示。
所包含的 4 個角色不是任何時候都要存在的,在有些應用環境下模式是可以簡化的,如以下兩種情況。
(1) 如果只有一個具體構件而沒有抽象構件時,可以讓抽象裝飾繼承具體構件,其結構圖如圖 4 所示。
[外鏈圖片轉存中…(img-QT2YoKXa-1606732760147)]
圖4 只有一個具體構件的裝飾模式
(2) 如果只有一個具體裝飾時,可以將抽象裝飾和具體裝飾合并,其結構圖如圖 5 所示。
[外鏈圖片轉存中…(img-8sultfh1-1606732760149)]
圖5 只有一個具體裝飾的裝飾模式
總結
以上是生活随笔為你收集整理的装饰模式(装饰设计模式)详解——小马同学@Tian的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Git下载项目到本地
- 下一篇: ANTLR使用访问器遍历语法树