设计初衷: 通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。
要点: 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为
Java的IO标准库提供的InputStream根据来源可以包括:
FileInputStream:从文件读取数据,是最终数据源;
ServletInputStream:从HTTP请求读取数据,是最终数据源;
Socket.getInputStream():从TCP连接读取数据,是最终数据源;
如果我们要给FileInputStream添加缓冲功能,则可以从FileInputStream派生一个类:
BufferedFileInputStream extends FileInputStream如果要给FileInputStream添加计算签名的功能,类似的,也可以从FileInputStream派生一个类:
DigestFileInputStream extends FileInputStream如果要给FileInputStream添加加密/解密功能,还是可以从FileInputStream派生一个类:
CipherFileInputStream extends FileInputStream这还只是针对FileInputStream设计,如果针对另一种InputStream设计,很快会出现子类爆炸的情况。
因此,直接使用继承,为各种InputStream附加更多的功能,根本无法控制代码的复杂度,很快就会失控。
为了解决这个问题,JDK首先将InputStream分为两大类:
一类是直接提供数据的基础InputStream,例如:
FileInputStream
ByteArrayInputStream
ServletInputStream
...
一类是提供额外附加功能的InputStream,例如:
BufferedInputStream
DigestInputStream
CipherInputStream
...
上述这种通过一个“基础”组件再叠加各种“附加”功能组件的模式,称之为Filter模式(或者装饰器模式:Decorator)。它可以让我们通过少量的类来实现各种功能的组合:
简单来说,装饰模式在基类上增加的每一个功能(简单称做功能类)都能够互相调用,每一个功能类之间都是平行层级的,与直接使用extend不同,直接继承的类之间是树状结构而不是平行的。这样就避免功能之间的嵌套。
假如,我们基于A类,又实现了三个不同的功能类(A1,A2,A3),但是此时我们需要同时用到A1和A2的功能,按照直接继承的思路而言,就要继承A1或者A2实现A12的一个新类。但是对装饰模式而言,我们不需要新建一个类,直接A1(A2),相当于A1去调用A2,这样就可以同时实现A1A2的功能。
例子下面举个例子:
假如我们要去买一个汉堡,汉堡有多种类,还可以选择是否添加生菜、辣椒等配料。这样给汉堡定价格,就可以使用装饰者模式。
这里如果我们直接使用继承来做的话,假如有n种配料,我们就需要将n种配料之间的不同组合的类全部实现出来,直接爆炸。
如果使用装饰者模式来做,我们只需要定义n个类就可以完成汉堡定价的功能,因为n个类之间可以相互调用,我们可以很方便的类的组合。
下面是代码:
首先是汉堡的基类,这里定义了一个抽象类,返回了汉堡的名字和价格。
package decorator; public abstract class Humburger { protected String name; public String getName(){ return name; } public abstract double getPrice(); }然后是汉堡的种类,这里用的鸡腿堡
package decorator; public class ChickenBurger extends Humburger { public ChickenBurger(){ name = "鸡腿堡"; } @Override public double getPrice() { return 10; } }配料的基类,返回配料的名称
package decorator; public abstract class Condiment extends Humburger { public abstract String getName(); }生菜(装饰的第一层)
package decorator; public class Lettuce extends Condiment { Humburger hburger; public Lettuce(Humburger burger){ this.hburger = burger; } @Override public String getName() { return hburger.getName()+" 加生菜"; } @Override public double getPrice() { return hburger.getPrice()+1.5; } }辣椒(装饰者的第二层)
package decorator; public class Chilli extends Condiment { Humburger hburger; public Chilli(Humburger burger){ this.hburger = burger; } @Override public String getName() { return hburger.getName()+" 加辣椒"; } @Override public double getPrice() { return hburger.getPrice(); //辣椒是免费的哦 } }