总章目录,设计模式(一)基本介绍
一 、定义
装饰模式:指在不改变现有对象结构的情况下,若要扩展此功能,装饰着提供了比继承更有弹性的替代方式。
tip:为什么说比继承更有弹性,若我们修改基类,通过继承实现的所有子类均需实现和修改方法。
二、结构
装饰模式主要包含以下角色。
Component:抽象构件类,定义抽象接口接收附加责任的对象。
ConcreteComponent:具体构件类,实现抽象构件,通过装饰角色添加职责。
Decorator:抽象装饰类,继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
ConcreteDecorator:具体装饰类,实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
三、代码示例
思考下,我们需要对星巴克各种进行描述,并计算其价格,我们怎么更好的去计算价格,如果使用继承的话,又怎么去考虑变化。
看到上面的装饰模式类图,我们可以看到装饰者和被装饰者都有相同的接口,原因是:装饰者必须能取代被装饰者。
因此,无论咖啡中加载什么配料,其本体任然是对饮的的咖啡。
五、简单实现
Component:咖啡(描述,价格)
public abstract class Coffee {
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public abstract double cost();
}
ConcreteComponent:浓咖啡 50 拿铁30
public class EspressoCoffee extends Coffee {
public EspressoCoffee() {
setDescription("浓咖啡");
}
@Override
public double cost() {
return 50d;
}
}
public class LatteCoffee extends Coffee {
public LatteCoffee() {
setDescription("拿铁");
}
@Override
public double cost() {
return 30d;
}
}
Decorator:
public abstract class CoffeeDecorator extends Coffee {
public abstract String getDescription();
}
ConcreteDecorator:
public class Milk extends CoffeeDecorator {
//**注意这里的对象保存之前的状态
Coffee coffee;
public Milk(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return "牛奶";
}
@Override
public double cost() {
return 1.2d + coffee.cost();
}
}
public class Mocha extends CoffeeDecorator {
Coffee coffee;
public Mocha(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return "摩卡";
}
@Override
public double cost() {
return 8.5d + coffee.cost();
}
}
最后我们点咖啡,并计算价格了
public class DecoratorTest {
@Test
public void DecoratorTest() {
//拿铁 + 牛奶 + 牛奶 + 摩卡=30+1.2+1.2+8.5
Coffee latteCoffee = new LatteCoffee();
latteCoffee = new Milk(latteCoffee);
latteCoffee = new Milk(latteCoffee);
latteCoffee = new Mocha(latteCoffee);
System.out.println("拿铁价格:" + latteCoffee.cost());
Coffee espressoCoffee=new EspressoCoffee();
System.out.println("浓咖啡:" + espressoCoffee.cost());
}
}
打印日志:
拿铁价格:40.9
浓咖啡:50.0
其实,通过上述示例我们基本就可以李军装饰者的范围和模式了。当然,若我们还是不能很好的理解的话,可以去浏览下Java I/O ,其就是通过装饰者模式实现的。