目录
-
-
- 8、装饰器模式
-
-
- [8.1 装饰器模式(Decorator)](#8.1 装饰器模式(Decorator))
- [8.2 装修(举例)](#8.2 装修(举例))
- [8.3 化妆(示例)](#8.3 化妆(示例))
- [8.4 化妆品的多样化](#8.4 化妆品的多样化)
- [8.5 装饰器](#8.5 装饰器)
- [8.6 自由嵌套](#8.6 自由嵌套)
- [8.7 装饰器模式的各角色定义](#8.7 装饰器模式的各角色定义)
- [8.8 装饰器模式](#8.8 装饰器模式)
-
-
8、装饰器模式
8.1 装饰器模式(Decorator)
- 能够在运行时动态地为原始对象增加一些额外的功能
- 装饰器非常类似于"继承",它们都是为了增强原始对象的功能 ,区别在于方式的不同
- 后者是在编译时(compile-time)静态地通过对原始类的继承完成
- 前者则是在程序运行时(run-time)通过对原始对象动态地"包装"完成,是对类实例(对象)"装饰"的结果
- 测试类结构
8.2 装修(举例)
- 不改变其原始结构的前提下使客体功能得到扩展、增强
- 以室内装潢为例
- 装修风格多种多样
- 朴素的毛坯房能给业主留有更大的装修选择空间,以根据自己的喜好进行二次加工
- 成品一定是由半成品加工而成的
- 灵活多变的装饰才会带来更多的可能,因此装饰器模式应运而生
8.3 化妆(示例)
-
首先对于任何妆容展示者必然对应一个标准的展示行为show()
-
我们将它抽象出来定义为接口Showable
-
Showable这个标准行为需要人去实现,定义女生类,素颜展示
- 如果客户端直接调用show()方法,就会出现素面朝天的结果
javapackage decorator; /** * 可展示者 **/ public interface Showable { /** * 标准展示行为 */ public void show(); }
- 化妆品我们在这里称为"装饰器": 化妆品装饰器类Decorator
javapackage decorator.base; import decorator.Showable; /** * 化妆品装饰器类 **/ public class Decorator implements Showable { /** *被装饰的展示者 */ Showable showable; /** * 构造时注入被装饰者 * @param showable */ public Decorator(Showable showable) { this.showable = showable; } @Override public void show() { //化妆品粉饰开始 System.out.print("粉饰【"); //被装饰者的原生展示方法 showable.show(); //粉饰结束 System.out.print("】"); } }
- 装饰器实现类
javapackage decorator.entity; import decorator.Showable; /** * 装饰器实现类 **/ public class Girl implements Showable { @Override public void show() { System.out.print("女生的素颜"); } }
- 测试类
javapackage decorator.base; import decorator.entity.Girl; /** * 客户端测试类 **/ public class Client { public static void main(String[] args) { //用装饰器装饰后后再展示 new Decorator(new Girl()).show(); } }
8.4 化妆品的多样化
-
化妆品的多样性决定了装饰器应该是多态化的
- 单个装饰器应该只负责自己的化妆功效
- 把化妆品按功能分类才能让用户更加灵活地自由搭配,用哪个或不用哪个由用户自己决定,而不是把所有功能都固化在同一个装饰器里
- 如果让所有化妆品类都实现Showable接口,每个化妆品类里都要引用这个被装饰者,这显然会导致代码冗余。
- Showable接口是能够满足多态化需求的,但它只是对行为接口的一种规范,极度的抽象并不具备对代码继承的功能
-
化妆品的多态化还需要接口与抽象类的搭配 使用才能两全其美,装饰器类的抽象化势在必行
- 我们将化妆品装饰器类修改为装饰器抽象类,这主要是为了不允许用户直接实例化此类
- 调用了被装饰者的show()方法,而不再做任何装饰操作
- 至于具体如何装饰则属于其子类的某个化妆品类的操作范畴了
- 抽象装饰器DecoratorAbstract
javapackage decorator.ab; import decorator.Showable; /** * 化妆品装饰器类: 抽象类 **/ public abstract class DecoratorAbstract implements Showable { protected Showable showable; public DecoratorAbstract(Showable showable) { this.showable = showable; } @Override public void show() { // 直接调用不加任何装饰 showable.show(); } }
-
实现类
- 粉底类FoundationMakeup、口红类Lipstick
javapackage decorator.ab; import decorator.Showable; /** * 粉底类 **/ public class FoundationMakeup extends DecoratorAbstract { /** * 调用抽象父类的构造注入 * @param showable */ public FoundationMakeup(Showable showable) { super(showable); } @Override public void show() { System.out.print("打粉底【"); showable.show(); System.out.print("】"); } }
javapackage decorator.ab; import decorator.Showable; /** * 口红类 **/ public class Lipstick extends DecoratorAbstract { public Lipstick(Showable showable) { super(showable); } @Override public void show() { System.out.print("涂口红【"); showable.show(); System.out.print("】"); } }
- 不用去实现Showable接口了,而是继承了装饰器抽象类,如此父类中对被装饰者的定义得以继承
- 重写show()方法, 加上自己特有的操作
-
客户端类Client
- 涂口红【打粉底【女生的脸庞】】
- 需要注意的是一系列构造产生的顺序
java
package decorator.ab;
import decorator.entity.Girl;
import decorator.Showable;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;
/**
* 客户端测试类
**/
public class Client {
public static void main(String[] args) throws FileNotFoundException {
test1();
test2();
}
private static void test1() {
Girl girl = new Girl();
/**
* 上粉底
*/
Showable foundationMakeup = new FoundationMakeup(girl);
/**
* 涂口红
*/
Showable medeupGirl = new Lipstick(foundationMakeup);
medeupGirl.show();
}
private static void test2() throws FileNotFoundException {
// 1.首先以文件file初始化
File file = new File("/压缩包.zip");
// 4.最外层再用压缩包输入流ZipInputStream进行最终装饰,使文件输入流具备Zip格式文件的功能
ZipInputStream zipInputStream = new ZipInputStream(
// 3.外层用缓冲输入流BufferedInputStream进行装饰,使文件输入流具备内存缓冲的功能
new BufferedInputStream(
// 2.构造文件输入流FileInputStream
new FileInputStream(file)
)
);
}
}
8.5 装饰器
- 如同"俄罗斯套娃"一般层层嵌套
- 其实装饰器模式在Java开发工具包(Java Development Kit,JDK)里就有大量应用
- 例如"java.io"包里一系列的流处理类InputStream、FileInputStream、BufferedInputStream、ZipInputStream等
- 举个例子,当对压缩文件进行解压操作时,我们就会用构造器嵌套结构进行文件流装饰,如:ab.Client.test2()
8.6 自由嵌套
- 装饰器模式最终的目的就在于"装饰"对象
- 其中装饰器抽象类 扮演着至关重要的角色,它实现了组件的通用接口
- 并且使自身抽象化 以迫使子类继承,使装饰器固定特性的延续与多态化成为可能
8.7 装饰器模式的各角色定义
- Component(组件接口):
- 所有被装饰组件及装饰器对应的接口标准 ,指定进行装饰的行为方法。如:展示接口Showable。
- ConcreteComponent(组件实现):
- 需要被装饰的组件 ,实现组件接口标准,只具备自身未被装饰的原始特性。如:类Girl
- Decorator(装饰器):
- 装饰器的高层抽象类,
- 同样实现组件接口标准 ,且包含一个被装饰的组件
- ConcreteDecorator(装饰器实现)
- 继承自装饰器抽象类的具体子类装饰器,可以有多种实现,在被装饰组件对象的基础上为其添加新的特性
- 如: 粉底类FoundationMakeup、口红类Lipstick
8.8 装饰器模式
- 装饰器模式可以将不同功能的单个模块规划至不同的装饰器类中
- 客户端可以根据自己的需求自由搭配各种装饰器,每加一层装饰就会有新的特性体现出来
- 最终使原始对象的特性动态地得到增强