設計模式——裝飾者模式:婚紗照收費的簡單實現

裝飾者模式

在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。java

裝飾者模式特色

  1. 裝飾者和被裝飾對象有相同的超類型。
  2. 你能夠用一個或者多個裝飾者包裝一個對象。 
  3. 既然裝飾者和被裝飾對象有相同的超類型,因此在任何須要原始對象(被包裝的)的場合,能夠用裝飾過的對象代替它。
  4. 裝飾者能夠在所委託被裝飾者的行爲以前與/或以後,加上本身的行爲,以達到特定的目的。
  5. 對象能夠在任什麼時候候被裝飾,因此能夠在運行時動態的,不限量的用你喜歡的裝飾者來裝飾對象。

裝飾者模式類圖

從上圖能夠看出,裝飾者和被裝飾者擁有共同的父類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

《設計模式——策略模式:會員價格體系的簡單實現.net

《福利送上,未滿十八歲勿點》設計

相關文章
相關標籤/搜索