1 概述
裝飾模式(Decorator),就是可以動態的給對象增加新的功能,它要求裝飾者對象和被裝飾者對象有着相同的抽象父類或者接口。
當然,也可以寫一個新的類來繼承舊的類,在新的類中增加方法或者重寫父類中的方法以此來達到擴展功能的目的,但是這樣做的話,依然在編譯的時候就定死了這個新的子類及其對象。想要動態的達到這一目的,就得使用這個模式了。
裝飾者模式有以下幾個要點(來自HeadFirst):
(1)裝飾者和被裝飾者有着相同的超類型
(2)可以使用多個裝飾者來裝飾一個對象
(3)對象可以在任何時候被裝飾,動態的
(4)在該模式的使用過程中,也會用到繼承,但是繼承的目的不是為了獲得行為,而是讓裝飾者和被裝飾者有同樣的超類型
2 示例
此模式的實現有如下幾個角色:
(1)抽象構件角色:定義一個抽象接口,來規范准備附加功能的類。
(2)具體構件角色:將要被附加功能的類,實現抽象構件角色接口。
(3)抽象裝飾者角色:持有對具體構件角色的引用並定義與抽象構件角色一致的接口。
(4)具體裝飾角色:實現抽象裝飾者角色,負責為具體構件添加額外功能。
我們此處的例子依然以手機生產為例,一個手機作為商品出售,除了機身之外,還有外殼和耳機等配件,價格自然不同,商家搭配成套餐出售,消費者也可以自定義買,最后有一個總價格。
首先定義個抽象的構件接口:
1 package org.scott.decorator; 2 /** 3 * @author Scott 4 * @date 2013-11-23 5 * @description 6 */ 7 public abstract class Component { 8 String description = "Unknown component"; 9 10 public String getDescription(){ 11 return description; 12 } 13 14 public abstract double getCost(); 15 }
然后是具體的手機Component:
1 package org.scott.decorator; 2 /** 3 * @author Scott 4 * @date 2013-11-23 5 * @description 6 */ 7 public class Phone extends Component { 8 9 public Phone(){ 10 description = "Phone"; 11 } 12 13 @Override 14 public double getCost() { 15 return 1000; 16 } 17 18 }
接着定義裝飾者:
1 package org.scott.decorator; 2 /** 3 * @author Scott 4 * @date 2013-11-23 5 * @description 6 */ 7 public abstract class Decorator extends Component{ 8 public abstract String getDescription(); 9 }
下面是兩種不同的套餐,也就是針對手機的兩種裝飾者類:
手機殼搭配銷售的套餐:
1 package org.scott.decorator; 2 /** 3 * @author Scott 4 * @date 2013-11-23 5 * @description 6 */ 7 public class PhoneShellSet extends Decorator { 8 Component com; 9 10 public PhoneShellSet(Component com){ 11 this.com = com; 12 } 13 14 @Override 15 public String getDescription() { 16 return com.getDescription() + " + phoneShell"; 17 } 18 19 @Override 20 public double getCost() { 21 return com.getCost() + 30.0; 22 } 23 24 }
耳機搭配銷售的套餐:
1 package org.scott.decorator; 2 3 /** 4 * @author Scott 5 * @date 2013-11-23 6 * @description 7 */ 8 public class EarpieceSet extends Decorator { 9 10 Component com; 11 12 public EarpieceSet(Component com) { 13 this.com = com; 14 } 15 16 @Override 17 public String getDescription() { 18 return com.getDescription() + " + Earpiece"; 19 } 20 21 @Override 22 public double getCost() { 23 return com.getCost() + 80.0; 24 } 25 }
功能代碼就是這些,寫個測試類跑一把:
1 package org.scott.decorator; 2 /** 3 * @author Scott 4 * @date 2013-11-23 5 * @description 6 */ 7 public class DecoratorTest { 8 public static void main(String [] args) { 9 Component component = new Phone(); 10 component = new PhoneShellSet(component); 11 component = new EarpieceSet(component); 12 13 System.out.println("所購買的的商品為:" + component.getDescription()); 14 System.out.println("一共花費:"+ component.getCost()); 15 } 16 }
運行結果:
所購買的的商品為:Phone + phoneShell + Earpiece
一共花費:1110.0
當然,套餐你想搞成什么樣就搞什么樣,可以動態的實現搭配組合,這就是裝飾者模式最大的優點了吧。
在JDK的源碼中最能體現裝飾者模式的,就是IO系列類,空了再分析分析那幾個東西,挺有意思~
上個圖吧,裝飾者模式的經典類圖: