装饰器模式
在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等。房子不管怎么装修,其本质都还是“房子”,相片不管加上什么类型的相框,本质任然是“相片”。在软件开发过程中,有时想用一些现存的组件,这些组件可能只是完成了一些核心功能,但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现。
定义
装饰器模式指在不改变现有对象结构的情况下,动态的给对象增加一些职责(即增加其额外功能)的模式,属于对象结构型模式,装饰器模式提供了一个全新的看待继承的视角,和比继承更具弹性的替代方案。
UML类图
使用场景
1.当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类
2.当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现
3.当对象的功能要求可以动态地添加,也可以再动态地撤销时
装饰器模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了。例如,InputStream 的子类FilterInputStream,OutputStream的子类FilterOutputStream,Reader的子类BufferedReader以及FilterReader,还有Writer的子类BufferedWriter、FilterWriter以及PrintWriter等,它们都是抽象装饰类。
示例
被装饰者抽象基类
/**
* 饮料抽象类
*/
public abstract class Beverage {
// 饮料描述
protected String description = "UnKnown Beverage";
// 返回饮料描述
public String getDescription() {
return description;
}
// 计算饮料价钱
public abstract double cost();
}
具体的被装饰者类
/**
* 黑烤咖啡(具体的被装饰者)
*/
public class DarkRoastCoffee extends Beverage {
public DarkRoastCoffee() {
description = "Dark Roast Coffee";
}
@Override
public double cost() {
return .75;
}
}
具体的被装饰者类
/**
* 浓咖啡(具体的被装饰者)
*/
public class Espresso extends Beverage {
public Espresso(){
description = "Espresso";
}
@Override
public double cost() {
return .99;
}
}
具体的被装饰者类
/**
* 自家混合咖啡(具体的被装饰者)
*/
public class HouseBlendCoffee extends Beverage {
public HouseBlendCoffee(){
description = "House Blend Coffee";
}
@Override
public double cost() {
return .89;
}
}
装饰者抽象基类
/**
* 条件装饰器
*/
public abstract class ConditionDecorator extends Beverage{
public abstract String getDescription();
}
具体装饰者类
/**
* 牛奶(具体的装饰者,用于给被装饰者增加职责)
*/
public class Milk extends ConditionDecorator {
Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return beverage.cost() + .11;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
}
具体装饰者类
/**
* 摩卡(具体的装饰者,用于给被装饰者增加职责)
*/
public class Mocha extends ConditionDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return beverage.cost() + .46;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
}
具体装饰者类
/**
* 奶泡(具体的装饰者,用于给被装饰者增加职责)
*/
public class Soy extends ConditionDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return beverage.cost() + .09;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
}
测试类
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
// 顾客需求如下:一杯DarkRoastCoffee,加双倍摩卡、一份牛奶。如何得到最终价钱+各种调料的一份订单?
// 1.一份DarkRoastCoffee
Beverage beverage = new DarkRoastCoffee();
// 加双倍摩卡
beverage = new Mocha(beverage);
beverage = new Mocha(beverage);
// 加牛奶
beverage = new Milk(beverage);
// 模拟订单描述
System.out.println(beverage.getDescription());
// 最终价钱
System.out.println(beverage.cost());
// 总结:简单来说就是对一个对象进行层层“加码”,动态赋予该对象其他的职责
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
// 顾客需求如下:一杯DarkRoastCoffee,加双倍摩卡、一份牛奶。如何得到最终价钱+各种调料的一份订单?
// 1.一份DarkRoastCoffee
Beverage beverage = new DarkRoastCoffee();
// 加双倍摩卡
beverage = new Mocha(beverage);
beverage = new Mocha(beverage);
// 加牛奶
beverage = new Milk(beverage);
// 模拟订单描述
System.out.println(beverage.getDescription());
// 最终价钱
System.out.println(beverage.cost());
// 总结:简单来说就是对一个对象进行层层“加码”,动态赋予该对象其他的职责
}
}
注意
敬请期待
优缺点
优点:
1.装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
2.通过使用不同装饰类及这些装饰类的排列组合,可以实现不同效果(例如一个房子,我可以使用中国田园风进行装修,也可以使用欧美风进行装修,这会产生不同的效果)
3.装饰器模式完全遵守开闭原则
缺点:
1.装饰器模式会增加许多子类,过度使用会增加程序得复杂性
在工作中的应用
敬请期待
设计原则工具箱
1.出应用中可能需要变化的部分,把它们独立出来,不要和那些不需要变化的代码混合在一起
2.针对接口(超类型)编程而不是针对具体的实现编程
3.多用组合少用继承
4.为了交互对象之间的松耦合设计而努力
5.类应该对扩展开放,对修改关闭