装饰者模式
前言
- 通过一个案例来解释为什么要用装饰模式
- 要完成这个案例的方法有很多种,传统方式是这样解决的:
- 根据上面一个方案的问题,提出了一个更好一点的方案:
- 但是方案二还是有问题,在增加和删除调料的时候,代码的维护量还是很多。
- 所以就是用装饰者模式去解决这一案例
基本介绍
- 装饰者模式: 动态的 将新功能 附加到对象上 。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则
- 这里提到的动态的将新功能附加到对象 和 ocp 原则 ,在后面的应用实例上会以代码的形式体现。
具体案例实现
- 类图
- 代码实现:
//饮品的抽象类
public abstract class Drink {
//描述
public String des;
//价格
public double price;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
//计算价格
public abstract double cost();
//打印咖啡名字
public abstract String print();
}
/* 咖啡品种 */
//咖啡抽象类
public class Coffee extends Drink{
//返回本来咖啡的价格
@Override
public double cost() {
return super.price;
}
//打印咖啡名字
@Override
public String print() {
return des;
}
}
//蓝山咖啡
public class BlueMountain extends Coffee{
public BlueMountain() {
setDes("蓝山咖啡");
setPrice(10.0);
}
}
//意大利咖啡
public class Espresso extends Coffee{
public Espresso() {
setDes("意大利咖啡");
setPrice(6.0);
}
}
/* 调料 */
//调料
public class Decorator extends Drink{
//已经点了饮料,想要在添加调料
private Drink drink;
public Decorator(Drink drink) {
this.drink = drink;
}
//计算费用
@Override
public double cost() {
return drink.cost()+price;
}
//打印咖啡样式
@Override
public String print() {
return des + drink.des;
}
}
//牛奶
public class Milk extends Decorator{
public Milk(Drink drink) {
super(drink);
setDes("牛奶");
setPrice(1.0);
}
}
//巧克力
public class Chocolate extends Decorator{
public Chocolate(Drink drink) {
super(drink);
setDes("巧克力");
setPrice(2.0);
}
}
//客户端
//客户端
public class Client {
public static void main(String[] args) {
//1. 先点一杯蓝山咖啡
Drink order = new BlueMountain();
System.out.println(order.print()+" 价格为:"+order.cost());
//2. 加牛奶
order = new Milk(order);
System.out.println(order.des+" 价格为:"+order.price);
System.out.println(order.print()+" 价格为:"+order.cost());
//2. 加巧克力
order = new Chocolate(order);
System.out.println(order.des+" 价格为:"+order.price);
System.out.println(order.print()+" 价格为:"+order.cost());
}
}
- 结果:
装饰者模式总结
- 装饰者模式的优点:
- 目的在于扩展对象的功能。装饰者模式提供比继承更好的灵活性。装饰是动态的,运行时可以修改的;继承是静态的,编译期便已确定好。
- 通过使用不同的装饰类及对它们的排列组合,可以创造出许多不同行为的组合。
- 装饰者模式的缺点:
- 利用装饰者模式,常常造成设计中有大量的小类,数量太多,会造成使用此API的人带来困扰,不容易理解。
- 采用装饰者在实例化组件时,将增加代码复杂度。一旦使用装饰者,不仅要实例化组件,同时要将组件实例包装进装饰者。
- 调试时不易排查错误。
- 适用场景:
- 需要扩展一个类的功能, 或给一个类增加附加功能。
- 需要动态地给一个对象增加功能, 这些功能可以再动态地撤销。
- 需要为一批的兄弟类进行改装或加装功能, 当然是首选装饰模式