Java設計模式(十):裝飾者模式Decorator

裝飾者模式:動態地將責任附加到對象上,若要擴展對象,裝飾者模式提供了比繼承更彈性的替代方案

要點: 裝飾者與被裝飾者擁有共同的超類,繼承的目的是繼承類型,而不是行爲

裝飾者包含一個超類的對象,這樣,可以在被裝飾者行爲前或者行爲後加上新的行爲,甚至取代原有的行爲

裝飾者會使程序中出現很多小類,增加使用難度

使用場景:對象由主體+許多可選的部件或者功能構成,使用繼承或者接口會產生很多類,且很難擴展。例如,現在需要一個三明治,主體是麪包,添加的材料有豬肉、羊肉、芹菜、青菜、雞蛋等等。


package com.iter.devbox.decorator.sandwich;

/**
 * 公共接口或抽象類
 * 所有成分的父類,抽象類有一個描述自己的方法和一個得到價格的方法,
 * 以及一個打印自身描述和價格的方法(該方法與另外兩個方法構成模板方法)
 * @author Shearer
 *
 */
public abstract  class Ingredient {
	public abstract String getDescription();

	public abstract double getCost();

	public void printDescription() {
		System.out.println(" Name      " + this.getDescription());
		System.out.println(" Price RMB " + this.getCost());
	}
}


package com.iter.devbox.decorator.sandwich;

/**
 * 被裝飾對象
 * 麪包類,因爲它是一個具體的成分,因此實現父類的所有的抽象方法。
 * 描述可以通過構造器傳入,也可以通過set方法傳入。同樣價格也是一樣的,我就很簡單地返回了。
 * @author Shearer
 *
 */
public class Bread extends Ingredient {
	private String description;

	public Bread(String desc) {
		this.description = desc;
	}

	public String getDescription() {
		return description;
	}

	public double getCost() {
		return 2.5;
	}
}


package com.iter.devbox.decorator.sandwich;

/**
 * 裝飾器對象,所有具體裝飾器對象父類。 它最經典的特徵就是:1.必須有一個它自己的父類爲自己的成員變量;2.必須繼承公共父類。
 * 這是因爲裝飾器也是一種成分,只不過是那些具體具有裝飾功能的成分的公共抽象罷了。
 * 在我們的例子中就是有一個Ingredient作爲其成員變量。Decorator繼承了Ingredient類。
 * 
 * @author Shearer
 *
 */
public abstract class Decorator extends Ingredient {
	protected Ingredient ingredient;

	public Decorator(Ingredient igd) {
		this.ingredient = igd;
	}

	public abstract String getDescription();

	public abstract double getCost();
}


package com.iter.devbox.decorator.sandwich;

/**
 * 具體的豬肉成分,同時也是一個具體的裝飾器,因此它繼承了Decorator類
 * @author Shearer
 *
 */
public class Pork extends Decorator {

	public Pork(Ingredient igd) {
		super(igd);
	}

	public String getDescription() {
		String base = this.ingredient.getDescription();
		return base + "\n" + "Decrocated with Pork !";
	}

	public double getCost() {
		double basePrice = ingredient.getCost();
		double porkPrice = 2;
		return basePrice + porkPrice;
	}
}


package com.iter.devbox.decorator.sandwich;

/**
 * 羊肉的包裝器。
 * @author Shearer
 *
 */
public class Mutton extends Decorator {
	public Mutton(Ingredient igd) {
		super(igd);
	}

	public String getDescription() {
		String base = ingredient.getDescription();
		return base + "\n" + "Decrocated with Mutton !";
	}

	public double getCost() {
		double basePrice = ingredient.getCost();
		double muttonPrice = 3.5;
		return basePrice + muttonPrice;
	}
}


package com.iter.devbox.decorator.sandwich;

/**
 * 芹菜的包裝器
 * @author Shearer
 *
 */
public class Celery extends Decorator {

	public Celery(Ingredient igd) {
		super(igd);
	}

	public String getDescription() {
		String base = ingredient.getDescription();
		return base + "\n" + "Decrocated with Celery !";
	}

	public double getCost() {
		double basePrice = ingredient.getCost();
		double celeryPrice = 0.6;
		return basePrice + celeryPrice;
	}

}


package com.iter.devbox.decorator.sandwich;

/**
 * 青菜的包裝器
 * @author Shearer
 *
 */
public class GreenGrocery extends Decorator {

	public GreenGrocery(Ingredient igd) {
		super(igd);
	}

	public String getDescription() {
		String base = ingredient.getDescription();
		return base + "\n" + "Decrocated with GreenGrocery  !";
	}

	public double getCost() {
		double basePrice = ingredient.getCost();
		double greenGroceryPrice = 0.4;
		return basePrice + greenGroceryPrice;
	}
}


package com.iter.devbox.decorator.sandwich;

public class Client {

	public static void main(String[] args) {
		//加豬肉和青菜的三明治
		Ingredient sandwich = new GreenGrocery(new Pork(new Bread("加豬肉和青菜的三明治")));
		sandwich.printDescription();
	}

}

運行結果:

 Name      加豬肉和青菜的三明治
Decrocated with Pork !
Decrocated with GreenGrocery  !
 Price RMB 4.9


最典型的裝飾器類就是Java IO中的 java.io.FilterInputStream


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章