目的
动态的给一个对象添加一些额外的职责。对于增加功能来说,该模式比生成子类更为灵活。
使用优点
- 采用装饰模式扩展对象的功能比采用继承方式更加灵活
- 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合
使用场景
装饰者模式UML小明很喜欢吃肉夹馍和手抓饼,手抓饼和肉夹馍都可以添加煎蛋、黄瓜、火腿等配料。但是这些配料是可选的,也就是装饰元素。
在这个例子中,我的类图如下:
煎饼和手抓饼.png
在本例子中,Pancake是UML中的Compoent,而手抓饼和肉夹馍都是Component的具体构建,Codiment是调料,是抽象装饰,Ham、Meat等是其的具体装饰。
具体代码如下:
/**
* 煎饼抽象类,对应UML中的Component
*/
public abstract class Pancake {
String desc;
public String getDesc(){
return desc;
}
//煎饼的价格
double price;
public double getPrice(){
return price;
}
}
/**
* 手抓饼,对应UML中的Concrete Component,
* 是Pancake的具体实现
*/
public class TornCake extends Pancake{
public TornCake(){
desc = "手抓饼";
}
@Override
public double getPrice(){
return 4;
}
}
public class Roujiamo extends Pancake {
public Roujiamo(){
desc = "肉夹馍";
}
@Override
public double getPrice(){
return 6;
}
}
/**
* 肉夹馍和手抓饼可以加的料,相当于UML中的抽象装饰
*/
public abstract class Condiment extends Pancake{
public abstract String getDesc();
}
/**
* 抽象装饰的具体实现,相当于UML中的具体装饰
* 可以加的料——黄瓜
*/
public class Cucumeber extends Condiment{
Pancake pancake;
public Cucumeber(Pancake pancake){
this.pancake = pancake;
}
@Override
public String getDesc(){
return pancake.getDesc() + ",黄瓜";
}
@Override
public double getPrice(){
return pancake.getPrice() + 1;
}
}
/**
* 装饰的具体实现
* 可以加的料——煎蛋
*/
public class Egg extends Condiment{
private Pancake pancake;
public Egg(Pancake pancake){
this.pancake = pancake;
}
@Override
public String getDesc(){
return pancake.getDesc() + ",煎蛋";
}
@Override
public double getPrice(){
return pancake.getPrice() + 2;
}
}
/**
* 可以加的料——火腿,装饰的具体实现
*/
public class Ham extends Condiment {
Pancake pancake;
public Ham(Pancake pancake){
this.pancake = pancake;
}
@Override
public String getDesc(){
return pancake.getDesc() + ",火腿";
}
@Override
public double getPrice(){
return pancake.getPrice() + 4;
}
}
测试类
public class Client {
public static void main(String[] args){
//新建一个手抓饼
Pancake torCake = new TornCake();
System.out.printf("%s 的价格是 %f\n",torCake.getDesc(),torCake.getPrice());
Pancake roujiamo = new Roujiamo();
roujiamo = new Egg(roujiamo);
roujiamo = new Ham(roujiamo);
roujiamo = new Cucumeber(roujiamo);
System.out.printf("%s 的价格是 %f\n",roujiamo.getDesc(),roujiamo.getPrice());
}
}
最后函数的输出结果如下;
手抓饼 的价格是 4.000000
肉夹馍,煎蛋,火腿,黄瓜 的价格是 13.000000
网友评论