『怎么用』代理模式

本文深入探讨了代理模式的概念及其在软件设计中的应用。介绍了代理模式如何为对象提供占位符或替身,控制对对象的访问,包括远程代理、虚拟代理、缓存代理、保护代理和智能引用代理等不同类型。并通过具体代码示例展示了代理模式的实现原理。
阐述

为一个对象提供一个占位符或者是替身,用以控制对这个对象的访问;
使用代理模式创建代理对象,代理对象用以访问被代理的对象。被代理对象可以远程对象、创建时开销大的对象、需要安全控制的对象。

  • 远程代理
    远程代理作为另一个JVM上对象的本地代表。调用代理上方法时,远程代理通过网络将请求传输到远程,并将结果再通过网络传输到本地,后返回给调用方。

  • 虚拟代理
    虚拟代理作为创建时开销大的对象的代表。虚拟代理经常直到我们真正需要一个对象的时候,才会去创建这个对象。在对象创建前、创建中的时候,这个对象的访问都由虚拟代理代表。在对象创建完成之后,虚拟代理才会将对象的访问委托给它所代理的对象。

    • 缓存代理(Caching Proxy)
      为开销大的运算结果提供暂时存储:它也允许多个客户共享结果,以减少计算或者网络延迟。
  • 保护代理
    根据权限不同,控制对被代理对象的访问。

    • 防火墙代理(Firewall Proxy)
      控制网络资源的访问,保护“主题”免于“坏客户”的侵害。
    • 智能引用代理 (Smart Reference Proxy)
      当主题被引用时,进行额外的动作,例如计算一个对象被引用的次数。
原理

在这里插入图片描述
在这里插入图片描述

例子

在这里插入图片描述

//subject
public interface PersonBean {
    String getName();
}
//real subject
public class PersonBeanImpl implements PersonBean {
    private String name;
    
    @Override
    public String getName() {
        return name;
    }
}
//handler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class NotOwnerInvocationHandler implements InvocationHandler {
	//持有project
    private PersonBean personBean;

    NotOwnerInvocationHandler(PersonBean personBean) {
        this.personBean = personBean;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("getIdCard".equals(method.getName())){
            throw new IllegalArgumentException("又不是你的资料,你瞅啥");
        }
        return method.invoke(personBean,args);
    }
}

import java.lang.reflect.Proxy;
public class ProxyUtil {

    public static PersonBean getOwnerProxy(PersonBean personBean){
        return (PersonBean) Proxy.newProxyInstance(
                personBean.getClass().getClassLoader(),
                personBean.getClass().getInterfaces(),
                new OwnerInvocationHandler(personBean)
        );
    }

    public static PersonBean getNotOwnerProxy(PersonBean personBean){
        return (PersonBean) Proxy.newProxyInstance(
                personBean.getClass().getClassLoader(),
                personBean.getClass().getInterfaces(),
                new NotOwnerInvocationHandler(personBean)
        );
    }
}

//test
private void drive(){
     PersonBean tom = new PersonBeanImpl("tom");

     PersonBean ownerProxy = ProxyUtil.getOwnerProxy(tom);
     System.out.println("ownerProxy.getIdCard() = " + ownerProxy.getIdCard());

     PersonBean notOwnerProxy = ProxyUtil.getNotOwnerProxy(tom);
     try {
         System.out.println("notOwnerProxy = " + notOwnerProxy.getIdCard());
     } catch (Exception e) {
         e.printStackTrace();
     }
}
总结
  • 你以为你用的是Object,但其实你用的是ProxyObject。“I am watching you , I can touch you .’”
  • ProxyInvocationHandler 都在 java.lang.reflect
  • Proxy创建代理对象,InvocationHandler可以决定是否要将请求真正委托给代理对象。
Q&A
### 使用代理模式设计收费系统的代码示例 代理模式是一种结构型设计模式,它允许通过创建一个中间层(即代理对象),控制对某个目标对象的访问。在这种情况下,可以利用代理模式来管理收费系统中的权限、日志记录以及性能优化等功能。 以下是使用 Java 编写的基于代理模式的收费系统设计示例: #### 接口定义 首先定义一个通用接口 `Chargeable`,表示所有可收费的对象都需要实现的功能。 ```java public interface Chargeable { double charge(double amount); } ``` #### 真实主题类 接下来定义真实的收费逻辑类 `RealChargeSystem`,它是实际完成收费操作的核心组件。 ```java public class RealChargeSystem implements Chargeable { @Override public double charge(double amount) { System.out.println("正在收取费用:" + amount + "元"); return amount; } } ``` #### 代理类 然后定义代理类 `ProxyChargeSystem`,用于拦截并扩展真实主题的行为。这里可以通过增加日志记录、权限校验或其他附加功能来增强原始行为。 ```java public class ProxyChargeSystem implements Chargeable { private final RealChargeSystem realChargeSystem; public ProxyChargeSystem(RealChargeSystem realChargeSystem) { this.realChargeSystem = realChargeSystem; } @Override public double charge(double amount) { if (amount <= 0) { System.err.println("错误:金额必须大于零!"); return 0; } // 添加前置处理逻辑,比如日志记录 logTransaction(amount); // 调用真实主题的方法 double result = realChargeSystem.charge(amount); // 可以在此处添加后置处理逻辑 confirmPayment(result); return result; } private void logTransaction(double amount) { System.out.println("记录交易:即将扣款" + amount + "元..."); } private void confirmPayment(double amount) { System.out.println("确认已成功扣除" + amount + "元!"); } } ``` #### 客户端调用 最后,在客户端中实例化代理对象,并通过代理间接调用真实主体的服务。 ```java public class MainApp { public static void main(String[] args) { // 创建真实主题 RealChargeSystem realChargeSystem = new RealChargeSystem(); // 创建代理对象并将真实主题传递给它 Chargeable proxyChargeSystem = new ProxyChargeSystem(realChargeSystem); // 测试收费功能 proxyChargeSystem.charge(100); // 正常情况下的收费测试 proxyChargeSystem.charge(-50); // 非法输入的情况测试 } } ``` --- ### 关键点说明 1. **代理的作用** 在上述例子中,`ProxyChargeSystem` 是代理类,负责在调用 `RealChargeSystem` 的核心业务之前或之后执行一些额外的操作,例如参数验证、日志记录和结果确认等[^1]。 2. **灵活性与扩展性** 这种设计使得我们可以轻松地向现有系统中引入新的功能而无需修改原有代码,完全遵循开闭原则(OCP)。如果未来需要加入更多复杂的逻辑,只需调整代理部分即可[^2]。 3. **可能存在的问题** 尽管代理模式提供了许多好处,但也可能导致程序运行效率降低,因为每次请求都需先经过一层或多层中介才能到达最终的目标对象[^1]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高级摸鱼工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值