在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。java
從上圖能夠看出,裝飾者和被裝飾者擁有共同的父類Componet,爲了方便後面的擴展,咱們加了一個裝飾者父類Decorator,讓Decorator去繼承Componet,而後讓衆多裝飾者去繼承Decorator。設計模式
生活中符合裝飾者模式的應用場景其實還挺多,就拿前陣子去拍婚紗照的經從來說吧,婚紗工做人員通常先會跟你總體說,拍什麼樣的場景,多少套衣服,怎麼去收費,而後在不改變原有收費的前提下,會跟你說精修入冊數量,每加一張,就加收多少錢。如今咱們來把這個分級收費模式抽象一下,假如說,咱們拍攝一張照片是40塊錢,精修一張40塊,入冊10塊。安插在裝飾者模式中,照片自己就成了咱們說的被裝飾者(ConcreteComponet),而精修和入冊則符合咱們對裝飾者的定義,分別爲DecoratorA,DecoratorB。接下來咱們來實現一下這個應用場景的類圖結構。ide
照片自己 | 照片入冊 | 照片精修 | |
費用 | 40 | 10 | 40 |
Format爲裝飾者父類與WeddingPhoto(被裝飾者)共同繼承了Photo。IsPhotoAlbum(入冊)與PhotoWithPs(精修)爲裝飾者,共同修飾WeddingPhoto。他們都擁有共同的行爲cost(),用於計算出價格,description屬性主要用於記錄信息,方便查看實現結果,可要可不要。測試
package decorate.base; /** * 照片父類 * @author vision */ public abstract class Photo { private String description=""; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } /** * 價格 * @param price * @return */ public abstract Double cost(); }
package decorate.format; import decorate.base.Photo; /** * Format(照片規格)裝飾者,擴展自Photo父類 * @author vision */ public abstract class Format extends Photo{ /** * 描述 * @param description * @return */ public abstract String getDescription(); }
package decorate; import decorate.base.Photo; /** * 被裝飾者:婚紗照 * @author vision */ public class WeddingPhoto extends Photo{ public WeddingPhoto() { setDescription(getDescription()+"WeddingPhoto(婚紗照)"); } @Override public Double cost() { return 40.0; } }
package decorate.format; import decorate.base.Photo; /** * 裝飾者:照片是否入冊 * @author vision */ public class IsPhotoAlbum extends Format{ private Photo photo; public IsPhotoAlbum(Photo photo) { this.photo=photo; } @Override public String getDescription() { return photo.getDescription()+"+IsPhotoAlbum(入冊)"; } @Override public Double cost() { // TODO Auto-generated method stub return 10.0+photo.cost(); } }
package decorate.format; import decorate.base.Photo; /** * 裝飾者:照片精修 * @author vision */ public class PhotoWithPs extends Format{ private Photo photo; public PhotoWithPs(Photo photo){ this.photo=photo; } @Override public String getDescription() { return photo.getDescription()+"+PhotoWithPs(精修)"; } /** * 照片精修,每張多加40塊 */ @Override public Double cost() { return 40.0+photo.cost(); } }
package decorate; import decorate.base.Photo; import decorate.format.IsPhotoAlbum; import decorate.format.PhotoWithPs; public class TestClass { public static void main(String[] args) { Photo weddingPhoto=new WeddingPhoto(); //精修 PhotoWithPs photoWithPs=new PhotoWithPs(weddingPhoto); System.out.println("最終選擇的照片爲:"+photoWithPs.getDescription()); System.out.println("最終單價爲:"+photoWithPs.cost()); //入冊 IsPhotoAlbum isPhotoAlbum=new IsPhotoAlbum(photoWithPs); System.out.println("最終選擇的照片爲:"+isPhotoAlbum.getDescription()); System.out.println("最終單價爲:"+isPhotoAlbum.cost()); } }
參考資料:《Head First 設計模式》this
相關文章:《設計模式——觀察者模式:天氣推送的兩種實現》spa