概述
目录
- 适配器模式
- 对象适配器(组合adaptee,实现target)
- 类适配器(继承adaptee,实现target)
- 接口适配器(抽象类空实现target)
- 代理模式
- 静态代理
- Jdk动态代理
- Cglib动态代理
- 装饰器模式
- 桥接模式
- 总结
适配器模式
被访问的接口target和实际提供服务的接口Adaptee不一致,则需要通过Adaptor(实现target接口)来适配adaptee接口。
对象适配器(组合adaptee,实现target)
类适配器(继承adaptee,实现target)
接口适配器(抽象类空实现target)
示例代码
package com.mx.server.designPattern.adaptor;
/**
* 适配器模式
*
* @author luohq
* @date 2021-08-10
*/
public class AdaptorPattern {
public static void main(String[] args) {
//被适配者
Adaptee adaptee = new Adaptee();
//对象适配器
Target target = new AdaptorObj(adaptee);
target.request();
//类适配器
target = new AdaptorClass();
target.request();
//接口适配器
AdapteeInterface adapteeInterface = new AdaptorAbs() {
@Override
public void method1() {
System.out.println("AdaptorAbs method1");
}
};
adapteeInterface.method1();
}
}
/**
* 目标
*/
interface Target {
void request();
}
/**
* 被适配者
*/
class Adaptee {
void specialRequest() {
System.out.println("Adaptee do");
}
}
/**
* ===============================================================
* 对象适配器 - 通过组合被适配者,实现目标接口的形式
* ===============================================================
*/
/**
* 适配器 - 对象适配器模式 - 组合adaptee
*/
class AdaptorObj implements Target {
private Adaptee adaptee;
public AdaptorObj(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
System.out.println("AdaptorObj do");
this.adaptee.specialRequest();
}
}
/**
* ===============================================================
* 类适配器 - 通过继承被适配者,实现目标接口的形式
* 单继承有限制,且会将adaptee方法也暴露在适配器adaptor中来,
* 但是可以根据需求重写adaptee中方法
* ===============================================================
*/
/**
* 适配器 - 类适配器模式 - 继承adaptee
*/
class AdaptorClass extends Adaptee implements Target {
@Override
public void request() {
System.out.println("AdaptorClass do");
super.specialRequest();
}
}
/**
* ===============================================================
* 接口适配器模式中被适配的对象是一个接口,
* 在我们不需要全部实现被适配接口中提供的方法时,可以设计一个抽象类先实现该接口,并空实现接口中的所有方法。
* 这样继承了该抽象类的子类就可以选择性的重写其中的方法,以达到想要的效果
* ===============================================================
*/
/**
* 被适配的接口
*/
interface AdapteeInterface {
void method1();
void method2();
void method3();
}
/**
* 适配器抽象类(空实现被适配接口中的所有方法)
*/
abstract class AdaptorAbs implements AdapteeInterface {
@Override
public void method1() {
}
@Override
public void method2() {
}
@Override
public void method3() {
}
}
代理模式
一个客户类client不想或者不能直接引用一个委托对象RealSubject,而代理类对象Proxy可以在客户类client和委托对象RealSubject之间起到中介的作用,其特征是代理类Proxy和委托类RealSubject实现相同的接口Subject
静态代理
静态代理是在编码阶段,就已经确定被代理的接口,再对其编译。在程序运行之前,代理类.class文件就已经被创建了。
/**
* 代理模式
*
* @author luohq
* @date 2021-08-12
*/
public class ProxyPattern {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject subject = new Proxy(realSubject);
subject.request();
}
}
/**
* ===============================================================
* 静态代理 - 被代理的接口在编码阶段就已经确认了
* 如下示例代理仅能对Subject进行代理
* ===============================================================
*/
/**
* 目标接口
*/
interface Subject {
void request();
}
/**
* 具体实现(被代理类)
*/
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request");
}
}
/**
* 代理类(实现目标接口Subject,组合具体实现类RealSubject)
*/
class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
System.out.println("proxy request before");
this.subject.request();
System.out.println("proxy request after");
}
}
Jdk动态代理
动态代理是在程序运行时通过反射机制动态创建的,即运行时才确定被代理的接口或类,JDK动态代理仅支持接口级别
的(仅能根据接口生成代理类)
package com.mx.server.designPattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK - 接口级动态代理
*
* @author luohq
* @date 2021-08-12
*/
public class JdkDynamicProxy {
public static void main(String[] args) {
//被代理的目标对象
Subject subject = new RealSubject();
//Proxy根据接口定义、代理回调处理器生成代理类
Subject subjectProxy = (Subject) Proxy.newProxyInstance(
Subject.class.getClassLoader(),
new Class[]{Subject.class},
new DynamicProxyHandler(subject)
);
//调用代理对象的方法
subjectProxy.request();
}
}
/**
* 动态代理 - 调用处理类
* 执行代理类的每个方法时,均会触发会invoke回调,
* 可在invoke中添加控制逻辑,进而再调用被代理对象的目标方法
*/
class DynamicProxyHandler implements InvocationHandler {
//被代理的对象
private Object subject;
public DynamicProxyHandler(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Dynamic proxy request before");
//调用被代理对象的目标方法
Object result = method.invoke(this.subject, args);
System.out.println("Dynamic proxy request after");
return result;
}
}
Cglib动态代理
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类
,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承
,所以不能对final修饰的类进行代理
。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Cglib动态代理
*
* @author luohq
* @date 2021-08-12
*/
public class CglibDynamicProxy {
public static void main(String[] args) {
//对class进行代理
Subject subjectProxy = (Subject) Enhancer.create(
RealSubject.class,
new CglibMethodInterceptor()
);
subjectProxy.request();
//对目标对象进行代理(适用于target对象已存在)
Subject subject = new RealSubject();
subjectProxy = (Subject) Enhancer.create(
RealSubject.class,
new CglibMethodInterceptorWithTarget(subject)
);
subjectProxy.request();
}
}
/**
* 方法拦截器 - 拦截父类方法
*/
class CglibMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib proxy request before");
//通过代理类的方法调用父类superclass方法
Object result = methodProxy.invokeSuper(object, args);
System.out.println("Cglib proxy request after");
return result;
}
}
/**
* 方法拦截器 - 拦截具体target对象
*/
class CglibMethodInterceptorWithTarget implements MethodInterceptor {
//目标对象(被代理的对象)
private Object target;
public CglibMethodInterceptorWithTarget(Object target) {
this.target = target;
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib proxy request before");
//调用目标对象target的method方法
Object result = method.invoke(this.target, args);
System.out.println("Cglib proxy request after");
return result;
}
}
注:
对比Jdk和Cglib(对class进行代理)动态代理,
除了Jdk针对接口(实现接口)进行代理,Cglib通过继承类进行代理,
还会发现Jdk动态代理需要被代理类RealSubject
已经实例化
,
而Cglib可无需实例化RealSubject
,Cglib可通过继承RealSubject后再实例化代理类,
总结来说就是
Jdk动态代理存在2个对象(RealSubject,Proxy implements Subject)
,
Cglib动态代理仅存在1个对象(Proxy extends RealObject)
,
而这个特性在后续在SpringAop 切点表达式中this, target会有分别。
装饰器模式
装饰器模式通过组合对象以拓展对象功能
,相较于继承更具灵活性,继承关系是静态的,它在系统运行前就决定了,通过不同的具体装饰类以及这些装饰类的排列组合
,设计师可以创造出更多不同行为的组合。
例如汽车类car,想要给汽车添加不同的功能如下:
- 充电charge
- 加油refuel
- 自动驻车autohold
- ACC
如果采用传统继承方式通过子类的方式去实现,则每存在一种功能的组合则需要实现一个子类,而随着功能的增多、组合的增多,则子类也会越来越多,越来越难以维护,如下图。
而装饰器模式通过将每一种新添加的功能抽象为一个具体的装饰器decorator
,然后通过decorator的组合为对象拓展新的功能,可以比使用继承关系需要较少数目的类。
当仅有一个Decorator类时,可直接退化成代理模式
当仅有具体构件ConcreteComponent时,可将Decorator直接继承ConcreteComponent
示例代码
package com.luo.demo;
/**
* 装饰器 - 设计模式
*
* @author luohq
* @date 2021-08-15 11:39
*/
public class DecoratorPattern {
public static void main(String[] args) {
/** 具体的component */
Component component = new ConcreteComponent();
/** ConcreteDecorator1 */
Component decorator = new ConcreteDecorator1(component);
decorator.request();
//半透明模式 - 使用ConcreteDecorator1的特有属性
ConcreteDecorator1 concreteDecorator1 = (ConcreteDecorator1) decorator;
concreteDecorator1.setAddState(1);
System.out.println(concreteDecorator1.getAddState());
/** ConcreteDecorator2 */
decorator = new ConcreteDecorator2(component);
decorator.request();
//半透明模式 - 使用ConcreteDecorator2的特有方法
ConcreteDecorator2 concreteDecorator2 = (ConcreteDecorator2) decorator;
concreteDecorator2.addBehavior();
/** 任意组合装饰器 - 比继承更具灵活性(避免多种组合写多个子类进行实现) */
decorator = new ConcreteDecorator2(new ConcreteDecorator1(component));
decorator.request();
decorator = new ConcreteDecorator1(new ConcreteDecorator1(component));
decorator.request();
}
}
/**
* 抽象构件(Component)角色:给出一个抽象接口,已规范准备接收附加责任的对象
*/
interface Component {
void request();
}
/**
* 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类
*/
class ConcreteComponent implements Component {
@Override
public void request() {
System.out.println("ConcreteComponent request");
}
}
/**
* 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
*/
class Decorator implements Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void request() {
this.component.request();
}
}
/**
* 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
*/
class ConcreteDecorator1 extends Decorator {
private Integer addState;
public ConcreteDecorator1(Component component) {
super(component);
}
@Override
public void request() {
super.request();
System.out.println("ConcreteDecorator1 request");
}
public Integer getAddState() {
return addState;
}
public void setAddState(Integer addState) {
this.addState = addState;
}
}
/**
* 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。
*/
class ConcreteDecorator2 extends Decorator {
public ConcreteDecorator2(Component component) {
super(component);
}
@Override
public void request() {
super.request();
System.out.println("ConcreteDecorator2 request");
}
public void addBehavior() {
System.out.println("ConcreteDecorator2 addBehavior");
}
}
桥接模式
将抽象部分
与实现部分
进行分离,使它们可以独立变化,抽象和实现可以理解为两个独立变化的维度
,两个维度可以任意组合,且两个维度的变化互相不影响对方,可以理解为将静态继承改为了动态组合,避免两个层次之间建立静态的继承关系。
示例代码
/**
* 桥接模式
*
* @author luohq
* @date 2021-09-08
*/
public class BridgePattern {
public static void main(String[] args) {
//初始定义:抽象维度1 + 实现维度1
Abstraction abstraction = new ConcreteAbstraction1();
Implementor implementor = new ConcreteImplementor1();
//抽象维度1 + 实现维度1
abstraction.setImplementor(implementor);
abstraction.operation();
//抽象维度1 + 实现维度2
implementor = new ConcreteImplementor2();
abstraction.setImplementor(implementor);
abstraction.operation();
//抽象维度2 + 实现维度2
abstraction = new ConcreteAbstraction2();
abstraction.setImplementor(implementor);
abstraction.operation();
}
}
/**
* 抽象 - 抽象定义
*/
abstract class Abstraction {
/**
* 抽象关联实现
*/
protected Implementor implementor;
/**
* 抽象的变化维度
*/
abstract void operation();
public void setImplementor(Implementor implementor) {
this.implementor = implementor;
}
}
/**
* 抽象 - 抽象实现类1
*/
class ConcreteAbstraction1 extends Abstraction {
@Override
void operation() {
System.out.println("abstract op1");
super.implementor.operationImpl();
}
}
/**
* 抽象 - 抽象实现类2
*/
class ConcreteAbstraction2 extends Abstraction {
@Override
void operation() {
System.out.println("abstract op2");
super.implementor.operationImpl();
}
}
/**
* 实现 - 接口类
*/
interface Implementor {
/**
* 实现的变化维度
*/
void operationImpl();
}
/**
* 实现 - 具体实现类1
*/
class ConcreteImplementor1 implements Implementor {
@Override
public void operationImpl() {
System.out.println("implementor op1");
}
}
/**
* 实现 - 具体实现类2
*/
class ConcreteImplementor2 implements Implementor {
@Override
public void operationImpl() {
System.out.println("implementor op2");
}
}
总结
(1)适配器模式适用于接口转换
将Adaptee转换成实现目标接口Target的Adaptor,
适配器类Adaptor类关联(或继承)被适配类Adaptee,
适配器类Adaptor需要实现目标接口Target
(2)代理模式适用于访问控制、隔离
,隔离调用类和被调用类的关系
通过一个代理类去调用,
代理类Proxy包含被代理类RealSubject,
且代理类Proxy和被代理类RealSubject实现同一接口Subject
(3)装饰器模式适用于多维度可任意组合的增强
(每个维度即对应一个ConcreteDecorator),使用组合代替继承,减少继承类的数目
被装饰类ConcreteComponent和所有的装饰类Decorator、ConcreteDecorator必须实现同一个接口Component,
而且装饰器类Decorator必须持有被装饰的对象Component,
可以无限装饰(decorator装饰component、decorator装饰decorator)
(4)桥接模式适用于关联固定的两个维度,且两个维度皆可独立变化
,其实质为一个抽象维度对应一个实现维度,亦可扩展为一个抽象维度对应多个实现维度
抽象Abstraction关联实现Implementor
且抽象和实现均可独立变化
参考链接:
深度好文:设计模式之——适配器模式
设计模式—代理模式
JDK动态代理机制
Cglib动态代理
适配器模式、装饰器模式、代理模式的区别
简书 - java设计模式-装饰器模式(Decorator)
设计模式之桥接模式
最后
以上就是爱笑蜗牛为你收集整理的适配器模式、代理模式、装饰器模式、桥接模式的简单对比适配器模式代理模式装饰器模式桥接模式总结的全部内容,希望文章能够帮你解决适配器模式、代理模式、装饰器模式、桥接模式的简单对比适配器模式代理模式装饰器模式桥接模式总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复