架构型设计模式成员
门面模式
代理模式
装饰器模式
组合模式
享元模式
桥接模式
适配器模式
1. 代理模式
1.1 定义
为其他对象提供一种代理以控制对这个对象的访问
解决问题:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层
1.2 分类
1.2.1 静态代理
一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行
而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码
接口类
package com.zhunongyun.spring.proxy;
public interface Image {
void display();
void change(String imagePath);
}
--------------------------------------------------
接口的实现类
package com.zhunongyun.spring.proxy;
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("显示图片: " + fileName);
}
@Override
public void change(String imagePath) {
System.out.println("替换图片: " + imagePath);
}
private void loadFromDisk(String fileName){
System.out.println("加载图片: " + fileName);
}
}
-------------------------------------------------------
代理类
package com.zhunongyun.spring.proxy;
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
@Override
public void change(String imagePath) {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.change(imagePath);
}
}
---------------------------------------------------
测试类
package com.zhunongyun.spring.proxy;
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("---------------------");
// 图像不需要从磁盘加载
image.display();
}
}
输出结果:
加载图片: test_10mb.jpg
显示图片: test_10mb.jpg
---------------------
显示图片: test_10mb.jpg
1.2.2 动态代理
1.2.2.1 JDK 自带的动态代理
java.lang.reflect.Proxy: 生成动态代理类和对象
java.lang.reflect.InvocationHandler(处理器接口):可以通过invoke方法实现对真实角色的代理访问
每次通过 Proxy 生成的代理类对象都要指定对应的处理器对象
接口类
package com.zhunongyun.spring.proxy.dynamic;
public interface Subject {
int sellBooks();
String speak();
}
---------------------------------------------------------
接口实现类
package com.zhunongyun.spring.proxy.dynamic;
public class RealSubject implements Subject{
@Override
public int sellBooks() {
System.out.println("卖书");
return 1 ;
}
@Override
public String speak() {
System.out.println("说话");
return "张三";
}
}
------------------------------------------------------------------
动态代理类
package com.zhunongyun.study.toalibaba.spring.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 定义一个处理器
*
* @author gnehcgnaw
* @date 2018/11/5 19:26
*/
public class MyInvocationHandler implements InvocationHandler {
/**
* 这其实业务实现类对象,用来调用具体的业务方法
*/
private Object target;
/**
* 绑定业务对象并返回一个代理类
*/
public Object bind(Object target) {
//接收业务实现类对象参数
this.target = target;
//通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
//创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
/**
* @param proxy 代理类
* @param method 正在调用的方法
* @param args 方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=null;
System.out.println("预处理操作——————");
//调用真正的业务方法
result=method.invoke(target, args);
System.out.println("调用后处理——————");
return result;
}
}
-------------------------------------------------------------------
测试类
package com.zhunongyun.spring.proxy.dynamic;
import java.lang.reflect.Proxy;
/**
* 调用类
* @author gnehcgnaw
* @date 2018/11/7 20:26
*/
public class Client {
public static void main(String[] args) {
//真实对象
Subject realSubject = new RealSubject();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
//代理对象
Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Subject.class}, myInvocationHandler);
proxyClass.sellBooks();
proxyClass.speak();
}
}
------------------------------------------------------------------------
输出结果:
预处理操作——————
卖书
调用后处理——————
预处理操作——————
说话
调用后处理——————
1.2.2.2 CGlib动态代理
操作类
package com.zhunongyun.study.toalibaba.spring.proxy.cglib;
public class BookFacadeImpl {
public void addBook() {
System.out.println("新增图书...");
}
}
-------------------------------------------
CGlib代理类
package com.zhunongyun.study.toalibaba.spring.proxy.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class BookFacadeCglib implements MethodInterceptor {
/**
* 业务类对象,供代理方法中进行真正的业务方法调用
*/
private Object target;
/**
* 相当于JDK动态代理中的绑定
* @param target
* @return
*/
public Object getInstance(Object target) {
//给业务对象赋值
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
/**
* 实现回调方法
* @param obj
* @param method
* @param args
* @param proxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("预处理——————");
//调用业务类(父类中)的方法
proxy.invokeSuper(obj, args);
System.out.println("调用后操作——————");
return null;
}
}
------------------------------------------------
测试类
package com.zhunongyun.study.toalibaba.spring.proxy.cglib;
public class CglibDemo {
public static void main(String[] args) {
BookFacadeImpl bookFacade = new BookFacadeImpl();
BookFacadeCglib cglib = new BookFacadeCglib();
BookFacadeImpl bookCglib = (BookFacadeImpl) cglib.getInstance(bookFacade);
bookCglib.addBook();
}
}
----------------------------------------
输出结果
预处理——————
新增图书...
调用后操作——————
1.2.2.3 JDK动态代理与CGlib动态代理
JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法
CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理
©著作权归作者所有:来自51CTO博客作者悠娜的奶爸的原创作品,如需转载,请注明出处,否则将追究法律责任