前言
設計模式遍布我們編碼的每一個角落,例如JAVA剛入門那會做的第一個窗口程序用的Swing
中的ActionsListener
類就是觀察者模式實現的;以及我們文件操作接觸比較多的java.io
包內的類有許多就是裝飾者模式設計的。如果深入研究過Spring
源碼的人都會有這個感慨:Spring就是一些設計模式狂魔的作品
。
設計模式有一個非常重要的面向對象原則:針對接口編程,不針對實現編程
。
在我們debug排查故障或在寫程序的時候多多少少都會有看過Spring MVC
中的一些源碼,大多數人都會發現Spring
的代碼是比較難看懂的。那是因為我們大多都在用面向實現編程的思維去思考代碼。這樣去看一群設計模式狂魔整出來的東西當然是有相當大的難度的。我們需要看懂讀懂Spring
源碼,或者其他開源代碼必備的一個良好的功底那就是要熟悉常見的設計模式。
裝飾者模式
什么是裝飾者模式?我們來看看度娘的解讀
動態的將責任附加到對象上。若要擴展功能,裝飾者提供了有別于繼承的另一種選擇
我們先從我們所熟悉的java.io包內的裝飾者模式實現的類入手。我們來看一個熟悉的對象集合
BufferedInputStream
跟LinerNumberInputStream
都是擴展自FilterInputStream
,而FilterInputStream
是一個抽象的裝飾類。
裝飾java.io類
我們從上邊的java.io類中分析確認了裝飾者的重要用途:動態的將責任附加到對象上。
為什么要使用裝飾者模式
我們從設計一個簡單飲料店說起,飲料店中有原味奶茶,珍珠奶茶,綠茶,抹茶等;調料有糖,牛奶,奶泡等。我們會在第一時間在腦中進行一次類圖分析。
這種設計類似硬編碼形式在后期并不能做很好的擴展,并違背了一個非常重要的面向對象設計原則:類應該對擴展開放,對修改關閉
。
我們可以看出這種通過繼承設計的飲料店是有很大的缺陷:調料價錢出現改變是會使我們更改現有的代碼;一但出現新的調料或開發出新的飲料都需對現有代碼作比較大的改動。這樣的代碼可維護性是非常糟糕的。
接著我們用裝飾者模式做一次的重新設計
當我們組件與裝飾者模式組合時,就是再加入新的行為。例如紅豆+珍珠=紅豆珍珠奶茶,新的茶飲出來了,無需在添加一個新的類。
代碼實現
飲料抽象類
public abstract class Berverage {//飲料店抽象基類
public String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public abstract int Cost();
}
調料抽象類
public abstract class CondimentDecorator extends Berverage{
public abstract String getDescription();
}
飲料類
public class GreenTea extends Berverage {
public GreenTea () {
description = "this is a cup of green tea ";
}
public int Cost() {
return 5;
}
}
public class MilkTea extends Berverage {
public MilkTea() {
description = "this is a cup of milk tea";
}
public int Cost() {
return 6;
}
}
public class PearlsMilkTea extends Berverage {
public PearlsMilkTea() {
description = "this is a cup of pearls milk tea ";
}
public int Cost() {
return 2;
}
}
調料類
public class Milk extends CondimentDecorator {//牛奶
Berverage berverage;
public Milk( Berverage berverage) {
this.berverage = berverage;
}
public String getDescription() {
return berverage.getDescription()+"+milk";
}
public int Cost() {
return berverage.Cost()+3;
}
}
測試代碼
public class Application {
public static void main(String[] args) {
//珍珠奶茶
Berverage berverage1 = new PearlsMilkTea();
System.out.println(berverage1.getDescription() + " cost = " + berverage1.Cost());
//綠茶加牛奶
Berverage berverage = new GreenTea();
berverage = new Milk(berverage);
System.out.println(berverage.getDescription()+"cost = "+berverage.Cost());
}
}
測試結果
點題
裝飾者模式:動態的將責任附加到對象上。若要擴展功能,裝飾者提供了有別于繼承的另一種選擇
篇幅中講到了兩個重要的面向對象設計原則
- 針對接口編程,不針對實現編程
- 類應該對擴展開放,對修改關閉
The last
三人行,必有我師。在給大家分享干貨的同時,才疏學淺還望大家大刀予以斧正。也歡迎關注我的掘金或簡書,名稱為柴碼