[设计模式]-装饰器模式(Decorator)

来源:互联网 发布:java写游戏 编辑:程序博客网 时间:2024/06/07 03:34

装饰器模式——对象结构型模式

定义

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。

类图


  • Component(抽象构件角色):它是具体构件和抽象装饰类的共同父类,以规范准备接受附加责任的对象
  • ConcreteComponent(具体构件):抽象构件角色的子类(或实现),具体的组件对象,装饰器可以给它增加额外的职责
  • Docorator(装饰器):也是抽象构件角色的子类,持有一个抽象构件角色的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的
  • ConcreteDecorator(具体装饰类):具体的装饰类,实现为需要装饰的构件添加新的职责
注:该引用不一定是最原始的那个对象了,也可能是被其他装饰器装饰过后的对象,反正是实现同一个接口(父类),也就是同一类型

Java代码实现

如果我们要实现一个咖啡屋的订单系统,设计类时,如果要为m种咖啡(浓缩、深焙。。。)搭配的n种调料(豆浆、摩卡、糖、牛奶。。) 分别设计一个类。。简直是一个噩梦,这还没有考虑可能的新的需求变动
如何避免类爆炸问题,而又不违反开闭原则的基础上,弹性的搭配新的行为来应对未知的需求变动?装饰器模式正适合解决这类问题

咖啡屋订单实例


//饮料-抽象构件public abstract class Beverage {String description = "";public String getDescription() {return description;}public abstract double cost();}
//浓缩咖啡-具体构件1public class Espresso extends Beverage{public Espresso() {description = "浓缩咖啡(Espresso)";}@Overridepublic double cost() {return 1.99;}}
//调料-抽象装饰器public abstract class CondimentDecorator extends Beverage{@Overridepublic abstract String getDescription();}
//糖调料-具体装饰器public class Sugar extends CondimentDecorator{Beverage beverage ;public Sugar(Beverage beverage) {this.beverage = beverage;}@Overridepublic String getDescription() {return beverage.getDescription()+" + 糖 ";}@Overridepublic double cost() {return 0.20+beverage.cost();}}
咖啡屋订单
public static void main(String[] args) {Beverage coffee = new Espresso();//一杯浓缩咖啡System.out.println(coffee.getDescription()+" : $"+coffee.cost());coffee = new Milk(coffee);System.out.println(coffee.getDescription()+" : $"+coffee.cost());coffee = new Sugar(coffee);System.out.println(coffee.getDescription()+" : $"+coffee.cost());//+双份糖的深焙咖啡coffee = new DarkRoast();coffee = new Sugar(new Sugar(coffee));System.out.println(coffee.getDescription()+" : $"+coffee.cost());}/* Output:浓缩咖啡(Espresso): $1.99浓缩咖啡(Espresso) + 牛奶 : $2.29浓缩咖啡(Espresso) + 牛奶  + 糖 : $2.49深焙咖啡(DarkRoast) + 糖  + 糖  : $1.29 */

对象组合

装饰器模式能够动态地为对象添加功能,是从一个对象外部来给对象添加功能,相当于改变了对象的外观。从外部使用系统的角度看,就不再是使用原始的那个对象了,而是使用被一系列装饰器装饰过后的对象。这样就能够灵活的改变一个对象的功能,只要动态组合的装饰器发生了改变,那么最终所得到的对象的功能就发生了改变。另一个好处是装饰器功能的复用,可以给一个对象多次增加同一个装饰器,也可以用同一个装饰器来装饰不同的对象。而且符合面向对象设计中的一条基本规则:"尽量使用对象组合,而不是对象继承"

Java中装饰器模式

装饰模式在Java中最经典的应用就是I/O流,回忆一下,当我们使用流式操作读取文件内容时,怎么实现呢?示例如下:
public static void main(String[] args) throws IOException {DataInputStream dis = null;try {dis = new DataInputStream(new BufferedInputStream(new FileInputStream("D:/IOTest.txt")));byte[] bs = new byte[dis.available()];dis.read(bs);System.out.println("文件内容====>"+new String(bs));} finally{dis.close();}}

FileInputStream对象就相当于被装饰的对象,而BufferedInputStream对象和DataInputStream对象则相当于装饰器。而事实上Java I/O流的类图结构和装饰模式类图结构几乎是一样的

装饰器模式总结

装饰器模式的本质:动态组合
优点
  • 比继承更灵活。继承是静态的,而且一旦继承所有子类都有一样的功能。而装饰模式采用把功能分离到每个装饰器中,然后通过对象组合的方式,在运行时动态的组合功能,每个被装饰的对象最终有哪些功能,是由运行期动态组合的功能决定的
  • 更容易复用功能。有利于装饰器功能的复用,可以给一个对象多次增加同一个装饰器,也可以用同一个装饰器来装饰不同的对象
  • 简化高层定义。装饰模式可以通过组合装饰器方式给对象增添任意多的功能,因此在进行高层定义的时候,只需要定义最基本的功能就可以了,需要的时候结合相应装饰器完成需要的功能
缺点
可能会产生很多细粒度的对象

0 0