【设计模式】代理模式-Proxy

转载:https://www.cnblogs.com/yangchongxing/p/7654725.html

代理模式定义如下:

Provide a surrogate or placeholder for another object to control access to it。为另一个对象提供一个代理或占位符以控制对它的访问。

代理模式使用非常广泛,理解代理模式对解决实际问题大有裨益的。使用代理模式必须让代理类和目标类实现相同的接口。

我们以添加用户业务为例

复制代码
// 用户接口
package com.ycx.pattern.proxy;
public interface UserService {
    public void insertUser();
}
// 用户实现类
package com.ycx.pattern.proxy;
public class UserServiceImpl implements UserService {
    @Override
    public void insertUser() {
        System.out.println("添加用户...");
    }
}
复制代码

我们若要添加一个用户信息,需要new一个UserServiceImpl实例对象,然后调用insertUser方法。代码如下:

// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        UserService userServie = new UserServiceImpl();
        userServie.insertUser();
    }
}

执行结果
添加用户...

静态代理

若这时新添一个业务,添加用户要在insertUser方法的开始和结束追加日志,其他地方没有这个业务,所以添加用户的业务不能修改,这种情况可以使用代理实现。代码如下:

复制代码
// 代理
package com.ycx.pattern.proxy;
public class UserServiceProxy implements UserService {
    private UserService _userService;
    public UserServiceProxy(UserService userService) {
        _userService = userService;
    }
    @Override
    public void insertUser() {
        // 开始日志
        System.out.println("开始");
        _userService.insertUser();
        // 结束日志
        System.out.println("结束");
    }
}
// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        //  创建代理
        UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl());
        proxy.insertUser();
    }
}
复制代码

执行结果
开始
添加用户...
结束

上边的代理是比较随便的,只要实现了用户接口,都可以,再看看使用指定代理,这样代理就必须是制定的。代码如下:

复制代码
// 接口
package com.ycx.pattern.proxy;
public interface UserService {
    public void insertUser();
    public UserService getProxy();
}
// 实现类
package com.ycx.pattern.proxy;
public class UserServiceImpl implements UserService {
    private UserServiceProxy proxy = null;
    @Override
    public void insertUser() {
        // 关键代码是判断是不是自己指定的代理
        if (!isProxy()) {
            System.out.println("请使用指定的代理");
        } else {
            System.out.println("添加用户...");
        }
    }
    // 关键代码判断代理
    private boolean isProxy() {
        return this.proxy == null ? false : true;
    }
    // 关键代码返回自己的代理
    @Override
    public UserService getProxy() {
        this.proxy = new UserServiceProxy(this);
        return this.proxy;
    }
}
// 代理
package com.ycx.pattern.proxy;
public class UserServiceProxy implements UserService {
    private UserService _userService;
    public UserServiceProxy(UserService userService) {
        _userService = userService;
    }
    @Override
    public void insertUser() {
        System.out.println("开始");
        _userService.insertUser();
        System.out.println("结束");
    }
    @Override
    public UserService getProxy() {
        return this;
    }
}
// 客户端
package com.ycx.pattern.proxy;
public class Clicent {
    public static void main(String[] args) {
        // 只有使用自的代理才可以
        UserService proxy = new UserServiceImpl().getProxy();
        proxy.insertUser();
    }
}
复制代码

执行结果
开始
添加用户...
结束

我们来直接new一个对象执行,或者new一个代理,验证结果。代码如下:

1
2
3
4
5
6
7
8
// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        // 直接new一个对象
        new UserServiceImpl().insertUser();
    }
}

执行结果
请使用制定的代理

复制代码
// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        // 直接new一个代理
        UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl());
        proxy.insertUser();
    }
}
复制代码

执行结果
开始
请使用制定的代理
结束

从上面看都是不行的,只能使用指定的代理才可以。

下面是重头戏

动态代理-即面向横切面编程AOP(Aspect Oriented Programming)
InvocationHandler 是JDK提供的动态代理接口。Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

还是上面的例子,用动态代理实现代码如下:

复制代码
// 动态代理
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
    private Object object;
    MyInvocationHandler(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始");
        Object result = method.invoke(object, args);
        System.out.println("结束");
        return result;
    }
}
// 客户端
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
    public static void main(String[] args) {
        InvocationHandler h = new MyInvocationHandler(new UserServiceImpl());
        // 使用Proxy获得实例
        UserService proxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserService.class}, h);
        proxy.insertUser();
    }
}
复制代码

上面的实现方式客户端使用起来不方便,可以定义一个专门的客户代理。代码如下:

复制代码
// 动态代理
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
    private Object object;
    MyInvocationHandler(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始");
        Object result = method.invoke(object, args);
        System.out.println("结束");
        return result;
    }
}
// 客户代理
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class DynamicProxy {
    @SuppressWarnings("unchecked")
    public static <T> T newProxyInstance(T instance) {
        ClassLoader loader = instance.getClass().getClassLoader();
        Class<?>[] interfaces = instance.getClass().getInterfaces();
        InvocationHandler h = new MyInvocationHandler(instance);
        return (T) Proxy.newProxyInstance(loader, interfaces, h);
    }
}
// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        // 使用定制的代理返回实例
        UserService proxy = DynamicProxy.newProxyInstance(new UserServiceImpl());
        proxy.insertUser();
    }
}
复制代码

 待续...

posted @   翠微  阅读(178)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示