java模式之装饰器模式
定義:
裝飾器模式也叫作包裝器模式,只在不改變原有對象的基礎上,動態的給一個對象添加一些額外的職責。就增加功能來說,裝飾器模式相比生成子類更為靈活,屬于結構型設計模式
裝飾器模式提供了比繼承更有彈性的替代方案將功能附加到對象上。因此,裝飾器模式的核心功能是功能擴展,使用裝飾器模式可以透明且動態的擴展類的功能
應用場景:
用于擴展一個類的功能,或者給一個類添加附加職責
動態的給一個對象添加功能,這些功能可以再動態的被撤銷
需要為一批平行的兄弟類進行改裝或者加裝功能
UML類圖:
?
由上圖可知,裝飾器模式主要包含了4個角色;
抽象組建(Component):可以是一個接口或者抽象類,充當被裝飾類的原始對象,規定了被裝飾對象的行為
具體組件(ConcreteComponent):實現/繼承Component的一個具體對象,即被裝飾對象
抽象裝飾器(Decorator):通用的裝飾ConcreteComponent的裝飾器,其內部必然有一個屬性指向Component,其實現一般是一個抽象類,主要為了讓其子類按照其構造形式傳入一個Component,這是強制的通用行為。如果系統中裝飾邏輯單一,則并不需要實現許多裝飾器,可以直接省略該類,而直接實現一個具體裝飾器即可
具體裝飾器(ConcreteDecorator):Decorator的具體實現類,理論上,每個ConcreteDecorator都擴展了Component對象的一種功能
裝飾器模式的實現原理就是,讓裝飾器實現與被裝飾類相同的接口,使得裝飾器與被擴展類類型一致,并在構造函數中傳入該接口對象,然后再實現這個接口的被包裝類屬于同一類型,且構造函數的參數為其實現接口類,因此裝飾器模式具備嵌套擴展功能,這樣就能使用裝飾器模式一層一層的對底層被包裝類進行功能擴展了
通用寫法:
package com.design.pattern.decorator; ? public class Client {public static void main(String[] args) { ?ConcreteComponent c1 = new ConcreteComponent();ConcreteDecoratorA decoratorA = new ConcreteDecoratorA(c1);decoratorA.operation();System.out.println("---------------------------");ConcreteDecoratorB decoratorB = new ConcreteDecoratorB(c1);decoratorB.operation();System.out.println("---------------------------");ConcreteDecoratorB decoratorB1 = new ConcreteDecoratorB(decoratorA);decoratorB1.operation(); ?}static abstract class Component{public abstract void operation();}static class ConcreteComponent extends Component{ ?@Overridepublic void operation() {System.out.println("處理業務邏輯!!");}}static abstract class Decorator extends Component{protected Component component; ?public Decorator(Component component){this.component = component;} ?public void operation(){//轉發請求給組建對象,可以在轉發前后執行一些附加動作component.operation();}}static class ConcreteDecoratorA extends Decorator{ ?public ConcreteDecoratorA(Component component) {super(component);}private void ?operationFirst(){System.out.println("ConcreteDecoratorA裝飾operationFirst");}private void ?operationLast(){System.out.println("ConcreteDecoratorA裝飾operationLast");}public void operation(){operationFirst();super.operation();operationLast();}}static class ConcreteDecoratorB extends Decorator{ ?public ConcreteDecoratorB(Component component) {super(component);}private void ?operationFirst(){System.out.println("ConcreteDecoratorB裝飾operationFirst");}private void ?operationLast(){System.out.println("ConcreteDecoratorB裝飾operationLast");}public void operation(){operationFirst();super.operation();operationLast();}} }示例:
使用裝飾器模式解決煎餅加碼問題
下面用代碼來模擬給煎餅加碼的業務場景,先來看不用裝飾器模式的情況。首先創建一個煎餅Battercake類
package com.design.pattern.decorator; ? public class Battercake {protected String getMsg(){return "煎餅";}public int getPrice(){return 5;} }然后創建一個加雞蛋的煎餅BattercakeWithEgg類
package com.design.pattern.decorator; ? public class BattercakeWithEgg extends Battercake{ ?protected String getMsg(){return super.getMsg() + "+ 1個雞蛋";}public int getPrice(){return super.getPrice() + 1;} }在創建一個既加雞蛋又加香腸的BattercakeWithEggAndSausage類
package com.design.pattern.decorator; ? public class BattercakeWithEggAndSausage extends BattercakeWithEgg{protected String getMsg(){return super.getMsg() + "+ 1根香腸";}public int getPrice(){return super.getPrice() + 2;} }最后編寫客戶端測試代碼
package com.design.pattern.decorator; ? public class ClientTest {public static void main(String[] args) {Battercake battercake = new Battercake();System.out.println(battercake.getMsg() + ",總價格" + battercake.getPrice());BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();System.out.println(battercakeWithEgg.getMsg() + ",總價格" + battercakeWithEgg.getPrice());BattercakeWithEggAndSausage battercakeWithEggAndSausage = new BattercakeWithEggAndSausage();System.out.println(battercakeWithEggAndSausage.getMsg() + ",總價格" + battercakeWithEggAndSausage.getPrice());} }運行結果如下:
煎餅,總價格5 煎餅+ 1個雞蛋,總價格6 煎餅+ 1個雞蛋+ 1根香腸,總價格8運行結果沒有問題。但是,如果用戶需要一個加2個雞蛋和1根香腸的煎餅,則用現在的類結構是創建不出來的,也無法自動計算出價格,除非再創建一個類做定制。如果需求在變,那么一直加定制顯然是不科學的
下面用裝飾器模式來解決上面的問題。首先創建一個煎餅的抽象Battercake類。
package com.design.pattern.decorator.base; ? public abstract class Battercake {protected abstract String getMsg();protected abstract int getPrice(); }創建一個基本的煎餅(或者叫基礎套餐)BaseBattercake.
package com.design.pattern.decorator.base; ? public class BaseBattercake extends Battercake{@Overrideprotected String getMsg() {return "煎餅";}@Overrideprotected int getPrice() {return 5;} }然后創建一個擴張套餐的抽象裝飾器BattercakeDecotator類
package com.design.pattern.decorator.base; ? public abstract class BattercakeDecotator extends Battercake{private Battercake battercake; ?public BattercakeDecotator(Battercake battercake){this.battercake = battercake;}protected abstract void doSomething(); ?protected String getMsg(){return this.battercake.getMsg();}protected int getPrice(){return this.battercake.getPrice();} }接著創建雞蛋裝飾器EggDecorator
package com.design.pattern.decorator.base; ? public class EggDecorator extends BattercakeDecotator{public EggDecorator(Battercake battercake) {super(battercake);} ?@Overrideprotected void doSomething() {}protected String getMsg(){return super.getMsg() + "+1個雞蛋";}protected int getPrice(){return super.getPrice() + 1;} }創建香腸裝飾器SausageDecorator類
package com.design.pattern.decorator.base; ? public class SausageDecorator extends BattercakeDecotator{public SausageDecorator(Battercake battercake) {super(battercake);}@Overrideprotected void doSomething() {}protected String getMsg(){return super.getMsg() + "+1根香腸";}protected int getPrice(){return super.getPrice() + 2;} }在編寫客戶端測試代碼
package com.design.pattern.decorator.base; ? public class Client {public static void main(String[] args) {//買一個煎餅Battercake battercake;battercake = new BaseBattercake();//煎餅有點小,想再加1個雞蛋battercake = new EggDecorator(battercake);battercake = new EggDecorator(battercake);battercake = new SausageDecorator(battercake);System.out.println(battercake.getMsg() + ",總價: " + battercake.getPrice());} }運行結果如下圖所示:
煎餅+1個雞蛋+1個雞蛋+1根香腸,總價: 9裝飾器模式與代理模式區別
從代理模式的UML類圖和通用代碼實現上看,代理模式與裝飾器模式幾乎一摸一樣。代理模式的Subject對應裝飾器模式的Component,代理模式的RealSubject對應裝飾器模式的Concrete Component,代理模式的Proxy對應的裝飾器模式的Decorator。確實,從代碼實現上看,代理模式的確與裝飾器模式是一樣的,但是這兩種設計模式多面向的功能擴展面是不一樣的。
裝飾器模式強調自身功能的擴展。Decorator所做的就是增強ConcreteComponent的功能,主體對象為ConcreteComponent,著重類功能的變化。
代理模式強調對代理過程的控制。Proxy完全掌握對RealSubject的訪問控制,因此,Proxy可以決定對RealSubject進行功能擴展,功能縮減甚至功能散失,主體對象為Proxy。
優點:
裝飾器是繼承的有力補充,比繼承靈活,在不改變原有對象的情況下,動態地給一個對象擴展功能,即插即用。
通過使用不同裝飾類及這些裝飾類的排列組合,可以實現不同效果
裝飾器模式完全遵守開閉原則
缺點:
會出現更多的代碼,更多的類,增加程序的復雜性
動態裝飾在多層裝飾時會更復雜
總結
以上是生活随笔為你收集整理的java模式之装饰器模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微型计算机完成一个基本运算和判断,计算机
- 下一篇: C# word全文替换