java io 装饰者_Java IO 装饰者模式

1

装饰模式的角色

抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。

具体构件角色(Concrete Component):定义将要接收附加责任的类。

装饰角色(Decorator):持有一个构件(Component)对象的引用,并定义一个与抽象构件接口一致的接口。

具体装饰角色(Concrete Decorator):负责给构件对象“贴上”附加的责任。

2

Java IO中的装饰模式

在IO中,具体构件角色是节点流,装饰角色是过滤流。

FilterInputStream和FilterOutputStream是装饰角色,而其他派生自它们的类则是具体装饰角色。

3

装饰模式的特点

装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。

装饰对象包含一个真实对象的引用(reference)。

装饰对象接收所有来自客户端的请求,它把这些请求转发给真实的对象。

装饰对象可以在转发这些请求之前或之后附加一些功能。

这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。

4

程序实例

public interface Component{         public void doSomething();}

这是抽象构件角色,是一个接口。具体构件角色实现这个接口:

public class ConcreteComponent implements Component{         @Override          public void doSomething() {                         System.out.println("功能A");         }  }

5

装饰角色:public class Decorator implements Component{                             private Component component;                             public Decorator(Component component) {                                          this.component = component;                                     }                              @Override                              public void doSomething() {                                                component.doSomething();                                 }    }其中包含了构件角色的引用,方法调用中利用构件角色的方法。

6

具体装饰角色(两个):public class ConcreteDecorator1 extends Decorator{                     public ConcreteDecorator1(Component component) {                                super(component);                    }                 @Override                 public void doSomething() {                             super.doSomething();                             this.doAnotherThing();                     }                 private void doAnotherThing() {                             System.out.println("功能B");                     }}

7

public class ConcreteDecorator2 extends Decorator{                  public ConcreteDecorator2(Component component) {                              super(component);                      }                 @Override                  public void doSomething() {                         super.doSomething();                         this.doAnotherThing();                 }                 private void doAnotherThing() {                         System.out.println("功能C");                 }}

8

使用测试:

public class Client{         public static void main(String[] args) {                     Component component = new ConcreteComponent();                     Component component1 = new ConcreteDecorator1(component);                     component1.doSomething();                     System.out.println("-----------");                     Component component2 = new ConcreteDecorator2(component1);                     component2.doSomething();          }}

9

问题引入

咖啡店的类设计:

一个饮料基类,各种饮料类继承这个基类,并且计算各自的价钱。

饮料中需要加入各种调料,考虑在基类中加入一些布尔值变量代表是否加入各种调料,基类的cost()中的计算各种调料的价钱,子类覆盖cost(),并且在其中调用超类的cost(),加上特定饮料的价钱,计算出子类特定饮料的价钱。

缺点:类数量爆炸、基类加入的新功能并不适用于所有的子类、调料价钱的改变、新调料的出现都会要求改变现有代码;有的子类并不适合某些调料等情况……

10

设计原则

类应该对扩展开放,对修改关闭。

我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。

如能实现这样的目标,有什么好处呢?这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。

要让OO设计同时具备开放性和关闭性,不是一件容易的事,通常来说,没有必要把设计的每个部分都这么设计。

遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度。

我们需要把注意力集中在设计中最有可能改变的地方,然后应用开放-关闭原则。

11

用装饰者模式解决问题

解决咖啡店饮料问题的方法:

以饮料为主体,然后在运行时以调料来“装饰”饮料。

比如,顾客想要摩卡(Mocha)和奶泡(Whip)深焙咖啡(DarkRoast):

DarkRoast继承自Beverage,有一个cost()方法。

第一步,以DarkRoast对象开始;

第二步,顾客想要摩卡,所以建立一个Mocha装饰者对象,并用它将DarkRoast对象包装(wrap)起来;

第三步,顾客想要奶泡,所以建立一个Whip装饰者对象,并用它将Mocha对象包起来;(Mocha和Whip也继承自Beverage,有一个cost()方法);

最后,为顾客算钱,通过调用最外圈装饰者(Whip)的cost()就可以。Whip()的cost()会先委托它装饰的对象(Mocha)计算出价钱,然后在加上奶泡的价钱。Mocha的cost()也是类似。

12

装饰者模式的特点

装饰者和被装饰对象有相同的超类型。

可以用一个或多个装饰者包装一个对象。

因为装饰者和被装饰者具有相同的类型,所以任何需要原始对象的场合,可以用装饰过的对象代替。

装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。

对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。

13

装饰者模式的定义

装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值