设计模式: Proxy 代理模式

设计模式: Proxy 代理模式

简介

目的创建型结构型行为型
Factory Method 工厂方法Adapter 适配器Interpreter 解释器
Template Method 模版方法
对象Abstract Factory 抽象工厂
Builder 生成器
Prototype 原型
Singleton 单例
Adapter 适配器
Bridge 桥接
Composite 组合
Decorator 装饰器
Facade 外观
Flyweight 享元
Proxy 代理
Chain of Responsibility 职责链
Command 命令
Iterator 迭代器
Mediator 中介者
Memento 备忘录
Observer 观察者
State 状态
Strategy 策略
Visitor 访问者

参考

Design Patterns-Elements of Reusable Object-Oriented Software

完整示例代码

https://github.com/superfreeeee/Blog-code/tree/main/design_pattern/src/main/java/com/example/proxy/classic

正文

场景

先说说代理模式的应用场景。在 OOP 的编程思想当中,通常我们习惯将操作和关联数据封装成一个对象(Object),而我们操作的目标则是以对象为单位。然而很多时候我们可能并不希望直接访问对象,而是根据需要访问不同的代理对象(Proxy)

  1. 通过不同途径访问对象(二次请求、远程代理、编码) → \to R e m o t e P r o x y   远 程 对 象 Remote Proxy \space 远程对象 RemoteProxy 
  2. 对象缓冲(附加信息、静态信息缓冲) → \to V i r t u a l P r o x y   虚 拟 对 象 Virtual Proxy \space 虚拟对象 VirtualProxy 
  3. 检查、过滤使用者权限(访问控制) → \to P r o t e c t i o n P r o x y   保 护 对 象 Protection Proxy \space 保护对象 ProtectionProxy 

当然代理对象还能有其他用途,然而不论基于什么目的,代理的本质在于:建立一个新的对象,包裹并代理目标对象的必要操作,并在真正调用目标对象方法过程中(调用前 or 后)加入额外的其他操作、检查等,这就是一种代理。

模式结构

  • Subject 操作对象接口:定义目标对象的公共操作接口
  • RealSubject 操作对象实体:真正执行核心操作的对象
  • ProxySubject 操作对象代理:保存操作对象实体,并对实体的操作进行代理

代理模式的类型结构非常简单,我们对原本直接操作的对象(Real Subject)抽象出一个公共的操作接口(Subject),并定义一个新的**代理对象(Proxy)**用于代理一个对象实体的操作。

代码示例

下面给出一个极其简单的代码示例,本身并不代表任何功能,但是实现代理模式的精神

Subject 操作接口

package com.example.proxy.classic;

public interface Subject {
    void f(); // method1
    
    void g(); // method2
}

我们一共定义了两种操作接口

Real Subject 操作实体

首先我们先给出操作实体实现的具体操作

package com.example.proxy.classic;

public class SubjectImpl implements Subject {
    @Override
    public void f() {
        System.out.println("invoke function f");
    }

    @Override
    public void g() {
        System.out.println("invoke function g");
    }
}

Proxy Subject 操作代理

接下来的代理对象接受另一个操作对象作构造函数参数,这表示代理对象还能够多层嵌套的,我们调用一个代理对象的时候,调用的顺序可能如下图所示。

其他操作接口仅仅是对构造时保存的对象的操作进行代理,额外操作的体现是在执行前多输出加一个前缀。

package com.example.proxy.classic;

public class SubjectProxy implements Subject {

    private Subject subject;

    public SubjectProxy(Subject subject) {
        this.subject = subject;
    }

    private void prefix() {
        System.out.print("[Subject Proxy]");
    }

    @Override
    public void f() {
        prefix();
        subject.f();
    }

    @Override
    public void g() {
        prefix();
        subject.g();
    }
}

测试代码

最后给出测试代码和输出

package com.example.proxy.classic;
import org.junit.Test;
import static org.junit.Assert.*;

public class SubjectTest {

    @Test
    public void test() {
        Subject subject = new SubjectImpl();
        Subject proxy = new SubjectProxy(subject);
        subject.f();
        subject.g();
        proxy.f();
        proxy.g();
    }
}
invoke function f
invoke function g
[Subject Proxy]invoke function f
[Subject Proxy]invoke function g

我们建立了一个操作实体,并用它来创建了一个代理对象。前两个调用直接调用原对象的方法,可以看到直接输出两个字符串;后两次调用则是透过代理对象进行调用,与设想的一样,多了代理对象的前缀。

结语

代理模式本质上是对操作对象的一种保护,不论是访问远程对象或是需要进行访问管理控制,或是需要对对象的操作**附带额外信息、进行额外的操作(记录、编码)**等,简单来说就是对真正的对象操作进行一层包裹、一层封装。

同时代理模式也引出一个 OOP 编程设计中非常重要的一条思想:面对接口编程。我们必须接受面对接口编程的好处,仅仅只需要知道对象的模样(look like),而不是直接与对象的实际类型打交道,如此一来我们也就不需要区分操作对象的类型究竟是对象实体(Real Subject)还是代理对象(Proxy)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值