定义
动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案
设计原则
- 类应该对外扩展开放,对修改关闭
允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。
要点
- 装饰者和被装饰对象具有相同的超类型
- 可以一个或多个装饰者包装一个对象
- 在任何需要原始对象的场合,都可以用装饰过的对象代替它
- 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的
- 装饰者必须能取代被装饰者
下面是一个例子。
案例
街上有很多小摊,其中最常见的就是煎饼果子摊位,煎饼可以加火腿,加鸡蛋,加肉,在这里煎饼就是原类,而鸡蛋、火腿、等就是装饰者,他们都继承共同的超类,超类的代码如下:
//所有类的超类型
public interface IPancake {
//用来描述此类
String getDescription();
//价钱
double cost();
}
很简单,就是一个接口,定义了两个方法getDescription()
和cost()
。
接下来我们做一张煎饼,代码如下:
/**
* 煎饼
*/
public class Pancake implements IPancake{
private String mDescription = "煎饼";
@Override
public String getDescription() {
return mDescription;
}
/**
* 单张煎饼4元
* @return
*/
@Override
public double cost() {
return 4.0;
}
我们定义它的价钱为4块钱,名字为煎饼,然后一张不加任何东西的煎饼就完成了。
接下来我们该做装饰类了,首先我们需要一个装饰者抽象类,然后让所有的具体装饰者继承此类,代码如下:
/**
* 装饰抽象类
*/
public abstract class Decorator implements IPancake{
protected IPancake pancake;
public Decorator(IPancake pancake) {
this.pancake = pancake;
}
public abstract String getDescription();
}
该抽象类提供了一个构造方法,将要装饰的对象传进来,可以在此对象委托前后加上自己的行为,接下来写一个鸡蛋装饰者,代码如下:
public class EggDecorator extends Decorator {
public EggDecorator(IPancake pancake) {
super(pancake);
}
@Override
public String getDescription() {
return"鸡蛋"+pancake.getDescription();
}
@Override
public double cost() {
return 1.0 + pancake.cost();
}
}
看到了吗?在构造方法中传入要装饰的对象,而pancake
变量是在父类里声明的,这样子类也可以使用了,然后再看getDescription()
和cost()
方法中,把被装饰者的描述和价钱都附加到了装饰者的描述和价钱中,以达到我们的目的。
同理,火腿装饰者代码类似,如下所示:
public class HamDecorator extends Decorator{
public HamDecorator(IPancake pancake) {
super(pancake);
}
@Override
public String getDescription() {
return "火腿" + pancake.getDescription();
}
@Override
public double cost() {
return 1.5 + pancake.cost();
}
}
现在我想要:
- 煎饼
- 鸡蛋煎饼
- 火腿煎饼
- 鸡蛋火腿煎饼
我们在main
方法中做测试,代码如下:
public class DecoratorTest {
public static void main(String[] args){
//什么也不加
IPancake pancake = new Pancake();
System.out.println(pancake.getDescription()+" 价钱: " + pancake.cost());
//加一个鸡蛋
EggDecorator eggDecorator = new EggDecorator(pancake);
System.out.println(eggDecorator.getDescription()+" 价钱: " + eggDecorator.cost());
//加一个火腿
HamDecorator hamDecorator = new HamDecorator(pancake);
System.out.println(hamDecorator.getDescription()+" 价钱: " + hamDecorator.cost());
//加鸡蛋、火腿的煎饼
pancake = new HamDecorator(eggDecorator);
System.out.println(pancake.getDescription()+" 价钱: " + pancake.cost());
}
}
打印结果:
煎饼 价钱: 4.0元
鸡蛋煎饼 价钱: 5.0元
火腿煎饼 价钱: 5.5元
火腿鸡蛋煎饼 价钱: 6.5元
这样,我们需要的东西都出来了,算算价钱也完全正确。
最后给大家一个提醒
装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂,根据情况合理的使用设计模式才是王道。
网友评论