Skip to content

设计模式:代理模式

ZhangPan edited this page Jul 16, 2025 · 3 revisions

一、静态代理

代理模式即为其它对象提供一种代理控制对这个对象的访问。在代理模式中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

代理模式的结构图如下:

image

举一个代理模式的场景:

Ryan想在上海买一套房子,但是他又不懂房地产的行情,于是委托了中介(Proxy)来帮助他买房子。

我们把这个场景通过Java代码来实现一下:

1.抽象出接口

首先我们把买房子的一类人抽象出来一个接口,接口中有一个buyHouse的方法:

public interface IPersonBuyHouse {
	void buyHouse();
}

2.明确被代理的对象

Ryan想要买房子,于是他就需要实现这个IPersonBuyHouse接口:

public class Ryan implements IPersonBuyHouse{

	@Override
	public void buyHouse() {
		System.out.println("Ryan:I want buy a House...");
	}
}

3.寻找代理

由于Ryan不了解房地产行情,于是将买房子的事情委托给了中介(Proxy),因此中介(Proxy)也需要实现IPersonBuyHouse的接口。但是中介不是给自己买房子的,而是买给其它有购房需求者的,所以他应该持有一个IPersonBuyHouse。而此处的购房需求者就是Ryan.于是Proxy代码如下:

public class Proxy implements IPersonBuyHouse{
	
	private IPersonBuyHouse mIPerson;
	
	public Proxy() {
	    mIPerson=new Ryan();
	}
	
	@Override
	public void buyHouse() {
	    System.out.println("Proxy:I can help you to buy house");
	    mIPerson.buyHouse();
	}
}

接下来我们在Main方法种测试一下Proxy类:

public class ProxyTest {

	public static void main(String[] args) {
	    new Proxy().buyHouse();
	}
}

输出结果:

image

通过上面的例子可以看到静态代理是一个很简单的设计模式。

二、动态代理

1.静态代理的缺点

  • 由于代理类要实现与被代理类一致的接口,当有多个类需要被代理时,要么代理类实现所有被代理类的接口,这样会使代理类过于庞大;要么使用多个代理类,每个代理类只代理一个被代理类,但是这样又会需要构造多个代理类。

  • 当接口需要增加、删除、修改方法时,被代理类与代理类都需要修改,不易维护。

为了解决上述问题,可以使用动态代理,自动生成代理类。

2.使用JDK提供的接口实现动态代理

这里涉及到两个类:java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler接口

举个例子:

Ryan想在上海买一套房子,但是他又不懂房地产的行情,于是委托了中介(Proxy)来帮助他买房子。

使用动态代理实现,首先定义一个IPersonBuyHouse的接口,且有一个buyHouse的方法:

public interface IPersonBuyHouse {
  // 购买房子的方法,返回值代表是否成功购买
  boolean buyHouse(String name);
}

使用动态代理实现Ryan买房子的需求:

public static void main(String[] args) {
    InvocationHandler handler = new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 在执行购买逻辑前可以先做一些校验,对于不符合要求的不予执行,并返回false。这里省略不写了...
            
            if (method.getName().equals("buyHouse")) {
                System.out.println(args[0] + " will buy a house.");
            }
            // 返回true,表示成功购买
            return true;
        }
    };
    IPersonBuyHouse person = (IPersonBuyHouse) Proxy
            .newProxyInstance(IPersonBuyHouse.class.getClassLoader(), // ClassLoader
                    new Class[]{IPersonBuyHouse.class}, // 传入要实现的接口
                    handler); // 传入处理调用方法的InvocationHandler
    person.buyHouse("Ryan");
}

2. 动态代理原理

动态代理是在运行时根据某个接口生成对应的代理类的字节码,然后加载到JVM的,并创建这个接口的实例的过程。

对于第二节中的例子进行分析,通过Proxy.newProxyInstance这个方法会生成一个IPersonBuyHouse的实现类。假设生成的这个类叫Ryan,Ryan这个类实现了IPersonBuyHouse,并重写了buyHouse的方法。在这个buyHouse的方法中会调用InvocationHandler的invoke方法。

Ryan类的代码大致如下:

public class Ryan implements IPersonBuyHouse {
   // buyHouse的真正逻辑在这个匿名内部类的invoke方法中
   private InvocationHandler handler = new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
            // 被代理类真正执行的逻辑
            if (method.getName().equals("buyHouse")) {
                System.out.println(args[0] + " will buy a house.");
            }
            return true;
        }
    };

    @Override
    public boolean buyHouse(String name) {
        try {
            // 反射获取buyHouse这个Method
            Method buyHouseMethod = IPersonBuyHouse.class.getDeclaredMethod("buyHouse", String.class);
            // 将buyHouse的参数封装成一个数组
            Object[] params = new Object[1];
            params[0] = name;
            // 实际调用了InvocationHandler的invoke方法
            return (boolean) handler.invoke(this, buyHouseMethod, params);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return false;
    }
}

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally