装饰者模式:动态地将责任附加到对象上,若要扩展对象,装饰者模式提供了比继承更弹性的替代方案
运行结果:
要点: 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为
装饰者包含一个超类的对象,这样,可以在被装饰者行为前或者行为后加上新的行为,甚至取代原有的行为装饰者会使程序中出现很多小类,增加使用难度
使用场景:对象由主体+许多可选的部件或者功能构成,使用继承或者接口会产生很多类,且很难扩展。例如,现在需要一个三明治,主体是面包,添加的材料有猪肉、羊肉、芹菜、青菜、鸡蛋等等。
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