就在前几天,国家又出台了房地产政策,以促进那些有钱人买房。买房已经成为社会上一个热门话题,在中国人的心理,买房可是像成家立业一样的大事。那买房就能住吗?买房之后要达到人住的条件还需要进行装修。房屋装修又是一笔不菲的开销,花大价钱购买的房子那可得好好思考下装修相关事宜。自己肯定研究不明白,就去找装修公司。这时装修公司给你列举了他们负责的装修项目:
看到了吧,购买的房子如果想要达到居住的目的,还需要选择性的进行装修才行,除非你喜欢叙利亚风格。生活中像这样需要额外添加一些可选择性的功能再投入使用的产品还有很多。再比如说购买奶茶时,你还可以选择多加波波,少加糖,少加冰等选项。好,那同学们想象如何在代码中更好的实现这种场景呢?
此时你可能会想到,既然是在原有的基础上增加功能,那就使用继承。使用继承的方式只能解决一些场景,比如房屋装修的可选项会有很多,每一种都使用继承的话就会出现继承类激增的问题。此外,房屋装修可能是几种功能选择后的组合,这种使用继承就无法实现了。我们知道既然继承不能,那肯定应该就是组合方式。但是如何组合呢?由于不同种类功能组合种类太多,简单的组合方式肯定也无法穷尽。我们今天要讲解的装饰模式,实际上就能解决这种问题的组合方式的实现。
装饰模式(Decorator Pattern)的一般定义如下:
在不改变现有对象结构的情况下,动态地给一个对象增加一些额外的职责
既然是动态的,就无法使用继承的方式来实现。我们可以考虑将这些“职责”封装为一个个类,其主要设计目的就是为了组合增强目标对象。为了保证能组合多个“职责”,那么“职责”之间也应该是可以互相增强。因此,装饰模式能够实现增强不同额外功能,并且可以很灵活的组合不同额外功能。
概念总结:
理论太直白,无法说明白到底是怎样的组合方式呢?本章节将通过一个具体的案例来给出装饰模式的一般实现方式。
案例背景:我今天吃的炒饭,老板问我加点啥呢?火腿、花生米、玉米、肥牛还是鸡柳。晚上突然饿了,那就以这个为案例吧。原有产品就是炒饭,可选择增加的功能有很多,你可以不选择也可以选择其中几个组合起来。这种就十分适合使用装饰模式来描述。
定义炒饭抽象类:
/**
* 炒饭抽象类
*/
public abstract class FriedRice {
protected String name; // 每盘炒饭都有名字
protected double price; // 不同炒饭的价格不同
public FriedRice() {
}
public FriedRice(String name, double price) {
this.name = name;
this.price = price;
}
public abstract String getName();
public abstract double getPrice();
}
具体的一份普通炒饭类:
public class PlainFriedRice extends FriedRice{
public PlainFriedRice(String name, double price) {
super(name, price);
}
@Override
public String getName() {
return name;
}
@Override
public double getPrice() {
return price;
}
}
配料装饰器:
/**
* 配料装饰器
*/
public class IngredientDecorator extends FriedRice {
private FriedRice friedRice;
public IngredientDecorator(FriedRice friedRice) {
this.friedRice = friedRice;
}
@Override
public String getName() {
return friedRice.getName();
}
@Override
public double getPrice() {
return friedRice.getPrice();
}
}
火腿炒饭:
public class HamDecorator extends IngredientDecorator{
public HamDecorator(FriedRice friedRice) {
super(friedRice);
}
@Override
public String getName() {
return super.getName() + " + 火腿";
}
@Override
public double getPrice() {
return super.getPrice() + 2.0;
}
}
鸡柳炒饭:
public class ChickenDecorator extends IngredientDecorator {
public ChickenDecorator(FriedRice friedRice) {
super(friedRice);
}
@Override
public String getName() {
return super.getName() + " + 鸡柳";
}
@Override
public double getPrice() {
return super.getPrice() + 2.5;
}
}

如上代码及类图所示,为了能够实现对FriedRice具体实现类的增强,装饰类(如ChickenDecorator)通过组合的方式来实现增强后的逻辑。
为何什么这里通过继承IngredientDecorator呢?因为不同装饰类可能需要修改(或增强)的方法不同,那么其他方法不应该是装饰类来声明,意即装饰类应只重写其负责的业务逻辑。那其他方法就应该调用目标对象的方法。这部分由IngredientDecorator负责,可以看到IngredientDecorator会重写所有FriedRice方法,并且都是直接调用目标对象的方法。如果需要增加新的装饰类,就只需要新增一个继承IngredientDecorator的类并实现其所要增强的方法即可。
装饰模式的优点:
装饰的缺点:
我们在前面讲解代理模式一文中提到,实现代理模式的方式可分为继承与组合两种方式。那本文装饰模式和代理模式的区别在哪里呢?
此处再重申下两种模式的定义: