设计模式(六)—— 装饰模式
一、定义:
在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
二、特点:
- 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
- 装饰对象包含一个真实对象的引用(reference)
- 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
- 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
三、情景:
在深圳吃早餐,我一般会点蛋肉肠,即鸡蛋+肉+肠粉+豆浆,其中肠粉是主食,附加料是肉、鸡蛋,饮料是豆浆
下面的情景我们考虑,主食有肠粉(4元)、米粉(3元),配料有鸡蛋(1元)、肉(1.5元)、油条(2元),饮料有豆浆(1.5元)设计类来实现该情景,打印出消费单和费用。
1、主食类(StapleFood)
public abstract class StapleFood {
private String description = "什么都没点";
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public abstract double cost();
}
2、肠粉类(RiceNoodleRolls)
public class RiceNoodleRolls extends StapleFood{
public RiceNoodleRolls() {
super.setDescription("肠粉");
}
public double cost() {
return 4;
}
}
3、米粉类(RiceNoodles)
public class RiceNoodles extends StapleFood{
public RiceNoodles() {
super.setDescription("RiceNoodles");
}
public double cost() {
return 3;
}
}
4、配料装饰类(CondimentDecorator1)
public abstract class CondimentDecorator1 extends StapleFood{
@Override
public String getDescription() {
return super.getDescription();
}
}
5、鸡蛋类(Egg)
public class Egg extends CondimentDecorator1{
StapleFood food;
public Egg(StapleFood food) {
this.food = food;
}
@Override
public String getDescription() {
return food.getDescription()+",Egg";
}
public double cost() {
return 1+food.cost();
}
}
6、肉类(Meat)
public class Meat extends CondimentDecorator1{
StapleFood food;
public Meat(StapleFood food) {
this.food = food;
}
@Override
public String getDescription() {
return food.getDescription()+",Meat";
}
public double cost() {
return 1.5+food.cost();
}
}
7、饮料装饰类(CondimentDecorator2)
public abstract class CondimentDecorator2 extends CondimentDecorator1{
@Override
public String getDescription() {
return super.getDescription();
}
}
8、豆浆类(SoybeanMilk)
public class SoybeanMilk extends CondimentDecorator2{
CondimentDecorator1 condimentDecorator1;
public SoybeanMilk(CondimentDecorator1 condimentDecorator1) {
this.condimentDecorator1 = condimentDecorator1;
}
@Override
public String getDescription() {
return condimentDecorator1.getDescription()+",豆浆";
}
public double cost() {
return condimentDecorator1.cost()+1.5;
}
}
9、点餐类
public class ShenzhenRiceNoodleRolls {
public static void main(String[] args) {
/**
* 点餐1:肠粉,Egg,Meat,豆浆
*/
StapleFood food = new RiceNoodleRolls();
CondimentDecorator1 cd1 = new Egg(food);
cd1 = new Meat(cd1);
CondimentDecorator2 cd2 = new SoybeanMilk(cd1);
System.out.println(cd2.getDescription());//肠粉,Egg,Meat,豆浆
System.out.println(cd2.cost());//8.0
/**
* 点餐2:米粉,Egg,豆浆
*/
StapleFood food1 = new RiceNoodles();
CondimentDecorator1 cd3 = new Egg(food1);
CondimentDecorator2 cd4 = new SoybeanMilk(cd3);
System.out.println(cd4.getDescription());//RiceNoodles,Egg,豆浆
System.out.println(cd4.cost());//5.5
}
}
关于作者
后端程序员,五年开发经验,从事互联网金融方向。技术公众号「清泉白石」。如果您在阅读文章时有什么疑问或者发现文章的错误,欢迎在公众号里给我留言。