装饰器模式
装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
装饰器模式的结构: 原有功能类和装饰器类都必须实现同一个接口,并且装饰器类还需要聚合原有功能类。
主要解决: 一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
案例:
咖啡店卖咖啡,咖啡有美式咖啡、无因咖啡等。
咖啡的配料有:巧克力、牛奶等。
点一份咖啡+n种配料,那么要算出最终价钱,例如点美式咖啡+2份巧克力+1份牛奶,也就是点击的量和种类是随机的。
上图解释:
drink:这个类就是公共接口类,原有功能类和装饰器类都需要去实现它;
图左半部分为原有功能类;
Decorator:装饰器类,必须实现公共接口类(Drink)和聚合该公共接口类(Drink,聚合的这个类就是被装饰者);
图右半部分为实现的装饰器类;
上图解释:
LongBlack为最开始的被装饰者类,将LongBlack传入Milk类(装饰者类)后,形成一个新的被装饰者类,以此类推。
在装饰者模式中,多次装饰后,方法的调用其实就是递归调用;
/**
* 定义一个公共的抽象类,这个类会被装饰者和被装饰者继承,也就是说装饰者和被装饰者需要有共同的方法
*/
public abstract class Common {
public String des;
private float price = 0f;
public abstract float cast();
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
}
//以下是被装饰者
/**
* 定义一个咖啡的缓冲层,可以把咖啡的公共方法写在这里面
*/
public class Coffe extends Common {
public float cast() {
//因为咖啡只点一次,这里的价格就是它自己的价格
return super.getPrice();
}
}
/**
* 美式咖啡
*/
public class USACoffe extends Coffe {
public USACoffe() {
setDes("美式咖啡");
setPrice(8f);
}
}
//以下是装饰者
/**
* 定义一个装饰者的父类,该类必须组合被装饰者
*/
public class Decorator extends Common {
//common 这个是被装饰者
private Common common;
public Decorator(Common common) {
this.common = common;
}
public float cast() {
//super.getPrice()==配料自己的价格 common.getPrice()==这个是前面被装饰者的价格
//super.getPrice() + common.cast() 这是一句递归代码,common.cast()这个代码最终会指向USACoffe里面定义的价格
return super.getPrice() + common.cast();
}
@Override
public String getDes() {
//common.getDes()这个代码最终会指向USACoffe里面定义的描述
return des +" " +getPrice()+"&&"+common.getDes();
}
}
/**
* 定义一个牛奶配料,继承装饰者类
*/
public class Milk extends Decorator{
public Milk(Common common) {
super(common);
setDes("牛奶");
setPrice(1f);
}
}
/**
* 定义一个巧克力配料,继承装饰者类
*/
public class QiaoKeLi extends Decorator{
public QiaoKeLi(Common common) {
super(common);
setDes("巧克力");
setPrice(3f);
}
}
public class Client {
public static void main(String[] args) {
Common common = new USACoffe();//点一个美式咖啡
common = new QiaoKeLi (common);//点一个巧克力配料
common = new Milk(common);//点一个牛奶配料
System.out.println(common.cast());
System.out.println(common.getDes());
}
}