装饰器模式
定义
装饰器模式(Decorator Pattern)也叫包装模式(Wrapper Pattern),是指在不改变原对象的基础上通过构造方法将原对象注入Wrapper中,将功能附加到对象上,属于结构型模式。
装饰器核心:透明的动态扩展类的功能。
装饰器现实对照:煎饼 +鸡蛋+香肠 == 煎饼
适用场景
- 拓展类的功能或给类添加附加职责。
- 动态给对象添加功能,这些功能可以再动态的撤销。
通用写法
- 装饰者与被装饰者实现相同的接口,然后通过构造方法将被接口注入过来,装饰者通过实现接口相同的方法实现了在原对象的基础对功能的拓展;
- 由于装饰器和被装饰者属于同一类型(均为接口的实现),且构造函数参数为接口类,因此装饰器模式具备嵌套拓展功能。
//TODO 代码练习
构造体系,被装饰的对象通过构造方法注入装饰器中。
实现案例:InputStream、BufferedReader
装饰器模式和代理模式的对比
- 装饰器模式是一种特殊的静态代理模式;
- 装饰器模式强调自身功能的拓展,你要求煎饼+鸡蛋 ——装饰器(客户主动拓展,一层套一层,将功能选择权交给客户);
- 代理模式强调代理过程的控制,商家做好了一个加鸡蛋的煎饼,供你选择—代理(功能已拓展,客户无法主动);
装饰器模式优缺点
优点:
- 装饰器是继承的有力补充,比继承灵活,即插即用;
- 通过使用不同装饰类以及这些装饰类不同的排列组合,可以实现不同的效果;
- 遵守开闭原则;
缺点:
- 出现更多的装饰类,增加程序复杂性;
- 动态装饰时需要实现多次嵌套,更复杂;
场景:权限可以使用装饰器模式来设计
问题: 1.使用装饰器模式实现一个可根据权限动态扩展功能的导航条。
代理模式 -- 中介
定义
代理模式(Proxy Pattern) 是指为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到了中介作用,属于结构模式
适用场景
- 保护目标对象
- 增强目标对象
通用写法
代理模式一般包含三个角色
- 抽象对象(Subject):主要职责是存储了目标对象与代理的共同方法,该类可以是接口/抽象类;
- 目标对象(RealSubject):该类为被代理类,负责执行真正的业务逻辑。
- 代理对象(Proxy):该类为代理类,内部持有被代理对象的引用,客户端通过调用代理对象的方法,来间接访问目标对象的方法,通常代理对象会对被代理对象的方法进行增强。
分类
静态代理
特点:显示声明被代理对象
案例:日常开发中的三层结构
动态代理
特点:基本原理根据底层逻辑动态生成代理类,底层都是通过反射来实现的
动态代理和静态代理的区别:
动态代理不管被代理目标是什么都可以代理,静态代理的对象必须固定。
动态代理—JDK
JDK动态代理采用字节重组,代理对象通过实现InvovationHandler接口重新生成对象替代原对象,来到达动态代理的目的。
JDK动态代理生成对象的步骤:
动态生成源码.java 文件
-
Java文件输出到磁盘,保存为文件$Proxy0.java。
(JDK动态代理命名规则:$+Proxy+JDK维护的自增ID)
把.java文件编译成$Proxy0.class文件
把生成的.class文件加载到JVM中
返回新的代理对象
//TODO 动态代理原理简单实现
动态代理—CGlib
通过实现MethodInterceptor接口动态继承目标对象来实现动态代理的功能
CGlib动态代理采用了FastClass机制,在第一次执行MethodProxy.invoke()方法的时候回生成FastClass类并存放在缓存中。
FastClass机制:为代理类和被代理类各生成一个类,这个类会为代理类或被代理类的方法分配一个Index(int类型),这个index当做一个入参,FastClass就可以直接定位要调用的方法进行调用省去了反射调用的时间,所以调用效率比JDK通过反射调用高。
代理模式优缺点
优点:
- 将被代理对象与调用对象进行分离降低了系统的耦合性
- 代理可起到保护目标对象的作用,增加目标对象的功能。
缺点:
- 出现更多的代理类,增加程序复杂性;
- 客户端和目标对象之间增加了代理对象,使得请求处理速度变慢。
注意:目的类和代理类需要共同的继承体系(继承相同的父类或者实现相同的接口)