代理模式-静态代理

代理模式简述

代理模式(Proxy Pattern)是程序设计中的一种设计模式。

所谓的代理可以简单理解为是一个中介。举一个生活中常见的例子:假如小王需要请刘德华唱歌,但是小王自己联系不到刘德华本人,小王只能联系他的经纪人,那么这个经纪人就是刘德华的代理。

在编程世界中,这个[代理者]就是一个。这个类可以作为其它行为的接口。

代理模式的[统一建模语言(UML)

[统一建模语言(UML)](https://raw.githubusercontent.com/onlywyt/wyt-pic/main/img/2880px-Proxy_pattern_diagram.svg-20230529230514395.png)图

代理的分类

什么是静态代理

静态代理是代理模式的一种实现方式,它具有以下几个特点:

  1. 目标对象和代理对象实现的是同一个业务接口。UML 图中的 Proxy 类就是代理对象, RealSubject 类就是目标对象
  2. 目标对象必须实现接口。UML 图中的 Proxy 实现了接口 Subject
  3. 代理对象在程序的运行之前已经存在
  4. 能够做到对目标对象的灵活切换,但是无法完成功能的灵活切换

业务实现

唱歌。小王需要请刘德华唱歌,刘德华就是目标对象。

经纪人。经纪人就是代理对象。这个经纪人既可以跟小王对接,也可以跟车的刘德华对接。

小王,就是所谓的客户端。UML 中的 Client。

代码实现

  1. 定义买车的业务接口 Service
1
void buyCar();
  1. 目标对象 LiuDeHua
1
2
3
void buyCar(){
Sout("我正在唱歌");
}
  1. 定义代理对象Agent并实现与目标对象一样的接口;并实现买车动作前后需要完成的动作
1
2
3
4
5
6
7
void buyCar(){
Sout("谈价钱");
//买车的动作,需要目标对象自己完成
LiuDeHua liudehua = new LiuDeHua();
liudehua.buyCat();
Sout("唱完歌,结账");
}
  1. 测试
1
2
3
4
5
public static void main(String[] args) {
//new 出来代理类
Agent agent = new Agent();
agent.sing();
}

琢磨下:上述例子中,我们只能代理刘德华,那如果来了陈奕迅我们应该怎么办呢?

面向接口编程

类中的成员变量设计为接口,方法的形参设计为接口,方法的返回值设计为接口,调用时接口指向实现类

首先,在上面的例子中,我们的代理类 Agent在自己的类中new了一个 LiuDeHua的实例,然后完成了唱歌前的定价动作和唱歌后的结账动作。那么,这时候我们只能听到刘德华唱的歌。那如果我们现在想要听陈奕迅的歌,应该怎么办呢?难道在 Agent 中在 new 一个 ChenYiXun 的实例吗?我们的代理类(经纪人)每次只能代理一个实例(明星)啊。这时候,我们就要采用面向接口编程的方式了。

  1. 我们已经知道有一个接口 Service中有 sing()方法。那么接下来我们将Service 作为Agent 类的成员变量
1
2
3
4
5
public class Agent implements Service {

//类中的成员变量设计为接口
public Service target;
}
  1. 我们实现一个带有参数的构造方法:将 Service 作为参数传进去
1
2
3
4
5
6
7
8
9
10
public class Agent implements Service {

//类中的成员变量设计为接口
public Service target;

//传入目标对象
public Agent(Service target) {
this.target = target;
}
}
  1. 最后,我们将调用的方法,由直接 new 实现类改为接口指向
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Agent implements Service {

//类中的成员变量设计为接口
public Service target;

//传入目标对象
public Agent(Service target) {
this.target = target;
}
@Override
public void sing() {
System.out.println("谈价钱....");
//业务功能必须使用目标对象
//面向接口编程,调用时,接口指向实现类;target就是传进来的实现类,刘德华或者陈奕迅等等....
target.sing();
System.out.println("唱完结账.....");
}
}

MyTest 类中的代码:

  1. 第一版;此时 new Agent()调用的是无参构造
1
2
3
4
public static void main(String[] args) {
Agent agent = new Agent();
agent.sing();
}
  1. 第二版;new Agent(Service target)调用的是参数为 Service 接口的有参构造;此时,会调用 Agent 的有参构造方法

public Agent(Service target) {this.target = target;}

此时做到了接口指向实现类的动作

1
2
3
4
public static void main(String[] args) {
Agent agent = new Agent(new ChenYiXun());
agent.sing();
}

至此,我们实现了一个简单的静态代理,简单了解了面向接口编程的思想。