之前一直不是很清楚装饰模式,今天把设计模式重新看了下发现也没有多么难。总结一下,装饰器模式就是允许用户向现有对象添加新功能,而无需更改其结构。该模式通过创建一个包装原始类(Component)的装饰器类(Decortator),并提供其他功能,以保持类方法的签名完整。如下图:
下面举一个例子:
假设我们想要计算一下买房+装修的花费。房子有一室一厅、两室一厅等,装修的话需要灯、床、桌子、椅子等等。当然如果不用装饰模式的话想计算任意组合都需要单独实现一个类,比如一个带一张桌子的一室一厅需要新建一个OneBedroomWithOneTable类,如果又想要知道带两张桌子的一室一厅的话有需要新建另一个OneBedroomWithTwoTable类,如果想知道任意一种组合方式的花费就需要为每一种排列组合的都实现一个单独的类,这样肯定是不行的。这时候就可以使用装饰模式来解决了。
首先,定义一个抽象房屋类作为原始类:
public abstract class Apartment {
//房屋描述
public abstract String getDescription();
//房屋花费
public abstract double getCost();
}
通过这个原始类我们可以两个的房屋的实现类:
public class OneBedroom extends Apartment {
@Override
public String getDescription() {
return "一室一厅";
}
@Override
public double getCost() {
return 3000000;
}
}
public class TwoBedroom extends Apartment {
@Override
public String getDescription() {
return "两室一厅";
}
@Override
public double getCost() {
return 4000000;
}
}
OK,接下来我们需要对房屋进行装修的话需要定义一个装饰类,也就是所有房屋装饰的基类,此类必须继承自 Apartment :
public abstract class Decoration extends Apartment {
protected Apartment apartment;
//这里需要传入房屋类,可根据需要传入未装饰过得房屋或者已经装饰过得房屋
public Decoration(Apartment apartment){
this.apartment = apartment;
}
public String getDescription() {
return apartment.getDescription();
}
public double getCost() {
return apartment.getCost();
}
}
然后我们可以在Decoration的基础上实现不同的装饰:
public class Bed extends Decoration {
public Bed(Apartment apartment){
super(apartment);
}
@Override
public String getDescription() {
return apartment.getDescription() + " + 床";
}
@Override
public double getCost() {
return apartment.getCost() + 500;
}
}
public class Light extends Decoration {
public Light(Apartment apartment) {
super(apartment);
}
@Override
public String getDescription() {
return apartment.getDescription() + " + 灯";
}
@Override
public double getCost() {
return apartment.getCost() + 100;
}
}
public class Table extends Decoration {
public Table(Apartment apartment){
super(apartment);
}
@Override
public String getDescription() {
return apartment.getDescription() + " + 桌子";
}
@Override
public double getCost() {
return apartment.getCost() + 80;
}
}
最终的计算:
public static void main(String[] args) {
//首先买一个一室一厅
Apartment apartment = new OneBedroom();
//装修个灯
apartment = new Light(apartment);
//再买张桌子
apartment = new Table(apartment);
//再配张床
apartment = new Bed(apartment);
//一室一厅 + 灯 + 桌子 + 床; 花费: 3000680.0
System.out.println(apartment.getDescription() + "; 花费: " + apartment.getCost());
}
最终的类图如下(可以对比下第一张图):
Java IO使用的就是典型的装饰模式: