java設計模式-裝飾模式
裝飾模式可以在不改變一個物件本身功能的基礎上給物件增加額外的新行為,在現實生活中,這種情況也到處存在,例如一張照片,我們可以不改變照片本身,給它增加一個相框,使得它具有防潮的功能,而且使用者可以根據需要給它增加不同型別的相框,甚至可以在一個小相框的外面再套一個大相框。裝飾模式是一種用於替代繼承的技術,它通過一種無須定義子類的方式來給物件動態增加職責,使用物件之間的關聯關係取代類之間的繼承關係。在裝飾模式中引入了裝飾類,在裝飾類中既可以呼叫待裝飾的原有類的方法,還可以增加新的方法,以擴充原有類的功能。裝飾模式(Decorator Pattern):動態地給一個物件增加一些額外的職責,就增加物件功能來說,裝飾模式比生成子類實現更為靈活。裝飾模式是一種物件結構型模式。
包含角色:
① Component(抽象構件):它是具體構件和抽象裝飾類的共同父類,聲明瞭在具體構件中實現的業務方法,它的引入可以使客戶端以一致的方式處理未被裝飾的物件以及裝飾之後的物件,實現客戶端的透明操作。 ② ConcreteComponent(具體構件):它是抽象構件類的子類,用於定義具體的構件物件,實現了在抽象構件中宣告的方法,裝飾器可以給它增加額外的職責(方法)。 ③ Decorator(抽象裝飾類):它也是抽象構件類的子類,用於給具體構件增加職責,但是具體職責在其子類中實現。它維護一個指向抽象構件物件的引用,通過該引用可以呼叫裝飾之前構件物件的方法,並通過其子類擴充套件該方法,以達到裝飾的目的。 ④ ConcreteDecorator(具體裝飾類):它是抽象裝飾類的子類,負責向構件新增新的職責。每一個具體裝飾類都定義了一些新的行為,它可以呼叫在抽象裝飾類中定義的方法,並可以增加新的方法用以擴充物件的行為。
下面,我們將以“圖形見面窗體”為例,來對裝飾模式進一步理解學習。
/** * 抽象元件產品 */ public abstract class Component { public abstract void display(); } /** * 具體元件類:窗體元件 */ public class Window extends Component { @Override public void display() { System.out.println("顯示窗體!"); } } /** * 具體元件類:文字框元件 */ public class TextBox extends Component { @Override public void display() { System.out.println("文字框顯示!"); } }
/**
* 構件裝飾類:抽象裝飾類
*/
public abstract class ComponentDecorator extends Component {
private Component component; //維持對抽象構建型別的引用
//注入抽象構件型別的物件
public ComponentDecorator(Component component){
this.component = component;
}
public void display(){
component.display();
}
}
/**
* 具體裝飾者:滾動條裝飾
*/
public class ScrollBarDecorator extends ComponentDecorator {
public ScrollBarDecorator(Component component) {
super(component);
}
public void display() {
setScrollBar();
super.display();
}
// 具體裝飾方法
public void setScrollBar() {
System.out.println("為構件新增滾動條!");
}
}
/**
* 具體裝飾者:黑色邊框裝飾
*/
public class BlackBorderDecorator extends ComponentDecorator {
public BlackBorderDecorator(Component component) {
super(component);
}
public void display() {
setBlackBorder();
super.display();
}
// 具體裝飾方法
public void setBlackBorder() {
System.out.println("為構件增加黑色邊框!");
}
}
/**
* 客戶端呼叫
*/
public class Client {
public static void main(String[] args) {
Component component = new Window();
Component decorator = new BlackBorderDecorator(component);
decorator.display();
}
}
輸出結果:
為構件增加黑色邊框! 顯示窗體!
主要優點:
(1) 對於擴充套件一個物件的功能,裝飾模式比繼承更加靈活性,不會導致類的個數急劇增加。 (2) 可以通過一種動態的方式來擴充套件一個物件的功能,通過配置檔案可以在執行時選擇不同的具體裝飾類,從而實現不同的行為。 (3) 可以對一個物件進行多次裝飾,通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合,得到功能更為強大的物件。 (4) 具體構件類與具體裝飾類可以獨立變化,使用者可以根據需要增加新的具體構件類和具體裝飾類,原有類庫程式碼無須改變,符合“開閉原則”。
主要缺點:
(1) 使用裝飾模式進行系統設計時將產生很多小物件,這些物件的區別在於它們之間相互連線的方式有所不同,而不是它們的類或者屬性值有所不同,大量小物件的產生勢必會佔用更多的系統資源,在一定程式上影響程式的效能。 (2) 裝飾模式提供了一種比繼承更加靈活機動的解決方案,但同時也意味著比繼承更加易於出錯,排錯也很困難,對於多次裝飾的物件,除錯時尋找錯誤可能需要逐級排查,較為繁瑣。
適用場景:
(1) 在不影響其他物件的情況下,以動態、透明的方式給單個物件新增職責。 (2) 當不能採用繼承的方式對系統進行擴充套件或者採用繼承不利於系統擴充套件和維護時可以使用裝飾模式。不能採用繼承的情況主要有兩類:第一類是系統中存在大量獨立的擴充套件,為支援每一種擴充套件或者擴充套件之間的組合將產生大量的子類,使得子類數目呈爆炸性增長;第二類是因為類已定義為不能被繼承(如Java語言中的final類)。