文章目錄
- 1.概念
- 1.1 什么是裝飾器模式
- 1.2 優點與缺點
- 2.實現方式
- 3. Java 哪些地方用到了裝飾器模式
- 4. Spring 哪些地方用到了裝飾器模式
1.概念
1.1 什么是裝飾器模式
它允許用戶在不修改現有對象的代碼的情況下向對象添加新的功能;這種模式是通過創建一個包含該對象的包裝對象來實現的,從而擴展該對象的功能。
1.2 優點與缺點
優點:
1.靈活性和擴展性
:裝飾器模式允許在運行時向對象添加新的行為,提供了比繼承更大的靈活性。
2.遵守開閉原則
:裝飾器模式允許向系統添加新的行為而不需要修改現有代碼,這符合開閉原則(軟件實體應該對擴展開放,對修改關閉)。
3.代碼復用
:裝飾器可以被多個對象共享,這減少了代碼的重復,提高了代碼復用性。
4.對象功能增強
:在不改變原有對象的情況下,可以有選擇性地增強對象的功能。
5.組合優于繼承
:裝飾器模式使用對象組合而不是繼承來擴展功能,這有助于避免繼承層次可能帶來的復雜性和脆弱性。
缺點:
1.增加復雜性
:裝飾器模式可能會增加系統的復雜性,因為需要創建多個小對象來表示不同的功能。2.調試困難
:由于裝飾器可以嵌套使用,調試和理解運行時的行為可能會變得更加困難。
3.性能問題
:裝飾器模式可能會引入額外的性能開銷,因為需要創建額外的對象,并且可能需要通過多個裝飾器來解析方法調用。
4.設計復雜
:如果使用不當,裝飾器模式可能會導致設計變得復雜,特別是當裝飾器之間的關系變得復雜時。
5.接口限制
:裝飾器模式要求裝飾器和被裝飾的對象實現相同的接口,這在某些情況下可能是不切實際的。
2.實現方式
①定義接口
public interface Beverage {String getDescription();double cost();
}
②創建一個實現了Beverage接口的具體類SimpleCoffee
public class SimpleCoffee implements Beverage {@Overridepublic String getDescription() {return "Simple Coffee";}@Overridepublic double cost() {return 1.0;}
}
③定義一個裝飾器類CondimentDecorator,它也實現了Beverage接口,并持有一個Beverage對象的引用:
public abstract class CondimentDecorator implements Beverage {protected Beverage beverage;public CondimentDecorator(Beverage beverage) {this.beverage = beverage;}public abstract String getDescription();
}
④創建具體的裝飾器類,比如Milk、Sugar和Chocolate,它們都擴展了CondimentDecorator并添加了各自的成本和描述:
public class Milk extends CondimentDecorator {public Milk(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + ", Milk";}@Overridepublic double cost() {return beverage.cost() + 0.5;}
}public class Sugar extends CondimentDecorator {public Sugar(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + ", Sugar";}@Overridepublic double cost() {return beverage.cost() + 0.1;}
}public class Chocolate extends CondimentDecorator {public Chocolate(Beverage beverage) {super(beverage);}@Overridepublic String getDescription() {return beverage.getDescription() + ", Chocolate";}@Overridepublic double cost() {return beverage.cost() + 0.3;}
}
⑤ 使用
public class DecoratorDemo {public static void main(String[] args) {Beverage coffee = new SimpleCoffee();System.out.println(coffee.getDescription() + " $" + coffee.cost());coffee = new Milk(coffee);coffee = new Sugar(coffee);coffee = new Chocolate(coffee);System.out.println(coffee.getDescription() + " $" + coffee.cost());}
}
3. Java 哪些地方用到了裝飾器模式
Java I/O 流
:
Java的I/O庫廣泛使用了裝飾器模式來增強基本輸入輸出流的功能。例如,BufferedInputStream和BufferedOutputStream類通過裝飾基本的InputStream和OutputStream來提供緩沖功能。同樣,DataInputStream和DataOutputStream為基本的流添加了讀寫基本數據類型的能力。
Java Servlet API
:
Java Servlet API中的HttpServletRequestWrapper和HttpServletResponseWrapper類允許開發者通過裝飾原始的HttpServletRequest和HttpServletResponse對象來添加或修改功能。
Java動態代理
:
Java的動態代理機制允許在運行時創建一個實現了一組接口的代理類實例。這個代理實例實際上是一個裝飾器,它可以在不修改原始對象代碼的情況下,為原始對象添加新的行為,如事務管理、日志記錄等。
Spring框架
:
Spring框架在很多地方使用了裝飾器模式,例如在AOP(面向切面編程)中,Spring會創建代理對象來包裝目標對象,以實現事務管理、權限檢查等橫切關注點的功能。
Apache Commons IO
:
Apache Commons IO庫提供了一些裝飾器類,如ProxyInputStream和ProxyOutputStream,這些類可以用來創建自定義的流裝飾器。
JDBC
:
JDBC驅動程序有時會使用裝飾器模式來增強或修改原始的Connection、Statement或ResultSet對象的行為。
JAX-RS
:
JAX-RS(Java API for RESTful Web Services)中的客戶端API允許使用裝飾器模式來增強或修改Client、WebTarget、Invocation等對象的行為。
4. Spring 哪些地方用到了裝飾器模式
AOP
(面向切面編程):
Spring AOP允許通過聲明式方式添加橫切關注點(如日志記錄、事務管理、安全檢查等)到目標對象。Spring創建代理對象來包裝目標對象,這些代理對象在調用目標方法前后執行額外的代碼。這實際上是一種裝飾器模式的應用,它允許在不修改目標對象代碼的情況下增強其行為。
事務管理
:
在Spring中,事務管理通常是通過AOP實現的。Spring可以為目標方法創建一個代理,該代理在方法執行前后管理事務的開啟和關閉,而無需修改目標方法的代碼。
Spring Security
:
Spring Security使用方法攔截器來實現安全控制。它可以為目標方法創建代理,這些代理在方法執行前檢查用戶的權限,如果用戶沒有足夠的權限,則不允許執行目標方法。
Spring Data JPA
:
Spring Data JPA中的倉庫(Repository)可以通過自定義的實現來擴展。開發者可以創建一個自定義的倉庫實現,并通過Spring的配置將其與標準倉庫接口關聯起來。這實際上是在使用裝飾器模式來擴展倉庫的功能。
Spring WebFlux
:
Spring WebFlux中的WebFilter和WebExceptionHandler可以被視為裝飾器模式的應用。它們允許在請求處理的各個階段添加額外的處理邏輯,而不需要修改原始的處理器代碼。
Spring Cloud
:
在Spring Cloud中,裝飾器模式被用于實現服務斷路器、負載均衡等功能。例如,Hystrix斷路器可以通過裝飾原始的服務調用邏輯來添加斷路器功能,從而在服務調用失敗時提供備選方案。
Spring Boot
:
Spring Boot自動配置的原理也可以看作是裝飾器模式的一種應用。Spring Boot可以自動配置各種組件,如數據源、事務管理器等,這些自動配置的組件可以被用戶的自定義配置所增強或覆蓋。