设计模式是面向问题、场景而总结产生的设计思路。是解决问题的套路。23 种经典的设计模式。它们又可以分为三大类:创建型、结构型、行为型。
结构型 包含了 代理模式、 桥接模式、 装饰器模式、适配器模式、门面模式、组合模式、 享元模式。
代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。现实中如租房中介、售票黄牛、婚介、经纪人、太监都是代理。
1. 为什么使用代理模式
当需要扩展功能时,在原有业务功能执行的前后加入一些公共的服务。例如我们想给某个类方法加入缓存、日志、权限控制、资源开和释放、事务管理等都可以通过代理来实现功能扩张增强。代理模式符合开闭原则原则——对修改关闭,对扩展开放。
2. 静态代理
2.1 通过接口实现静态代理
代理模式是一种组合关系,将委托类组合在代理类内部,通过代理方法增加额外的功能来扩展功能。在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
RealWorker 类 是具体实现了compute方法的类,而WorkerProxy 持有了RealWorker 对象。在对外宣称的compute()服务时,WorkerProxy 可以“添油加醋”增加log();clean();
等方法,这样能实现对委托对象的功能增强。
public interface Worker {
void compute();
}
public class RealWorker implements Worker{
@Override
public void compute() {
System.out.println("real worker is computing");
}
}
public class WorkerProxy implements Worker {
private Worker realworker;
public void setRealworker(Worker realworker) {
this.realworker = realworker;
}
public WorkerProxy(Worker realworker) {
this.realworker = realworker;
}
private void log(){
System.out.println("log something");
}
private void clean(){
System.out.println("release resources");
}
@Override
public void compute() {
log();
realworker.compute();
clean();
}
}
经过测试运行。
public class Main {
public static void main(String[] args) {
Worker worker = new WorkerProxy(new RealWorker());
worker.compute();
}
}
运行结果如下
log something
real worker is computing
release resources
2.2 通过继承实现静态代理
当RealWorker类已经完成编写了,并没有提前实现Worker接口。那么可以通过继承的方法,来实现增强。
public class WorkerProxy2 extends RealWorker {
private void log() {
System.out.println("log something");
}
private void clean() {
System.out.println("release resources");
}
@Override
public void compute() {
log();
super.compute();
clean();
}
}
3. 动态代理
静态代理需要通过编码的方式实现,而动态代理可以在运行时动态创建。Java反射语法提供了动态代理所需要的功能。
- 定义Worker接口及实现类
public interface Worker {
void compute();
}
public class RealWorker implements Worker {
public void compute() {
System.out.println("real worker is computing");
}
}
- 定义一个InvocationHandler,实现
invoke(Object proxy, Method method, Object[] args)
方法,在反射调用方法时可以进行增强。
public class WorkerInvocationHandler implements InvocationHandler {
private Object o;
public WorkerInvocationHandler(final Object o) {
this.o = o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("prepare");
Object res = method.invoke(o, args);
System.out.println("clean");
return res;
}
}
- 编写测试类
public class Main {
public static void main(String[] args) {
Worker realWorker = new RealWorker();
//Worker realWorker2 = new RealWorker2();
InvocationHandler handler = new WorkerInvocationHandler(realWorker);
ClassLoader loader = realWorker.getClass().getClassLoader();
Class[] interfaces = realWorker.getClass().getInterfaces();
Worker proxyworker = (Worker) Proxy.newProxyInstance(loader, interfaces, handler);
proxyworker.compute();
}
}
运行结果
prepare
real worker is computing
clean
总结
代理模式常用于对功能需求进行增强,增加一些非业务性的功能,比如监控、统计、鉴权、限流、事务、幂等、日志。Spring AOP 基于动态代理实现了面向切面编程,对方法进行纵向增强,再通过编织,将软件的复杂性大大降低。其实RPC也是使用代理模式思想,在本地端代理了远程对象,使得远程方法调用如同本地调用一样。
设计模式系列在github上有一个开源项目,主要是本系列博客的demo代码。https://github.com/forestnlp/designpattern
如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。
您的支持是对我最大的鼓励。