1. 什么是代理模式?

官方定义是:为其他对象提供一种代理以控制对这个对象的访问。其实说白了让代理做你原来要做的事情。

2. 代理案例

举个例子,我们正常玩游戏,需要个人登录游戏账号,然后进行升级,这是一件漫长而又艰辛的事情,我们无法开外挂,因为要封号,于是我们找到代理厂家,沟通后代理商登录你的游戏账号进行升级,这就是代理

3. 静态代理

创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。

如图:

JAVA设计模式之代理模式静态代理_代理类


开始撸代码:

3.1 定义一个IGamePlayer接口

public interface IGamePlayer {
// 登录游戏
void login(String user, String password);
// 打怪
void killBoss();
}

3.2 定义一个玩家类

public class GamePlayer implements IGamePlayer {
private String name = "";

public GamePlayer(String _name) {
this.name = _name;
}

@Override
public void login(String user, String password) {
System.out.println("登录名为" + user + "的用户"+ this.name + "登录成功");
}

@Override
public void killBoss() {
System.out.println(this.name + "打boss");
}
}

3.3 定义一个代理类GamePlayerProxy

public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;

public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}

@Override
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}

@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
}

3.4 代理上玩家的号进行代练,定义一个Client进行测试

public class Client {
public static void main(String[] args) {
// 定义一个玩家
IGamePlayer player = new GamePlayer("张三");
// 定义一个代练,代练玩家的号
GamePlayerProxy proxy = new GamePlayerProxy(player);
proxy.login("zhangsan", "123");
proxy.killBoss();
}
}

4. 代理模式的扩展:普通代理和强制代理。

我们平时会听到代理分为​​透明代理​​​和​​普通代理​​​,
​​​透明代理​​​:用户不用设置代理服务器地址直接访问,即代理服务器对用户来说是透明的,用户不知道它的存在
​​​普通代理​​:普通代理和强制代理属于一类,普通代理用户必须知道代理的存在才能进行访问,即代理服务器对用户来说是不透明的。强制代理则调用者直接调用真实角色,不关心代理存在,代理的产生由真实角色决定。

4.1 普通代理:

结构如图,对上述结构做小部分修改。

JAVA设计模式之代理模式静态代理_代理类_02

4.1.1 接口不用变化,修改GamePlayer

public class GamePlayer implements IGamePlayer {
private String name = "";
// 变动地方
public GamePlayer(IGamePlayer _gamePlayer, String _name) throws Exception {
if (_gamePlayer == null) throw new Exception("无法创建真实角色");
else this.name = _name;
}

@Override
public void login(String user, String password) {
System.out.println("登录名为" + user + "的用户"+ this.name + "登录成功");
}

@Override
public void killBoss() {
System.out.println(this.name + "打boss");
}
}

4.1.2 修改代理类

public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;

public GamePlayerProxy(String _name) {
try {
gamePlayer = new GamePlayer(this, _name);
}catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}

@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
}

4.1.3 修改测试类

public class Client {
public static void main(String[] args) {
// 创建一个代理对象
IGamePlayer proxy = new GamePlayerProxy("张三");
// 代理对象对账号进行代理升级
proxy.login("zhangsan", "123");
proxy.killBoss();
}
}

运行结果完全相同,在该模式下,调用者只知道代理而不用知道真实的角色是谁,真正的主角修改灵活,对高层模块没有什么影响,该模式适合扩展性好的场合。

4.1 强制代理:

一般都是通过代理找到真实的角色,但是强制代理却是通过真实的角色找到代理角色,否则不能访问。
​​​举个例子​​:你有事情通过找到明星A去访问他的导演朋友,而不想直接找他的经纪人B去找,但是拨通A电话后A说太忙了,你去找他的经纪人

对上述图结构进行修改

JAVA设计模式之代理模式静态代理_直接访问_03

4.1.1 修改接口

public interface IGamePlayer {
// 登录游戏
void login(String user, String password);
// 打怪
void killBoss();
// 每个人都可以找到自己的代理
IGamePlayer getProxy();
}

4.1.2修改强制代理的真实角色GamePlayer

public class GamePlayer implements IGamePlayer {
private String name = "";
private IGamePlayer proxy = null;

public GamePlayer(String _name) {
this.name = _name;
}

@Override
public void login(String user, String password) {
if (this.isProxy()) {
System.out.println("登录名为" + user + "的用户" + this.name + "登录成功");
}else {
System.out.println("请使用指定代理访问");
}
}

@Override
public void killBoss() {
if (this.isProxy()) {
System.out.println(this.name + "打boss");
}else {
System.out.println("请使用指定代理访问");
}
}

@Override
public IGamePlayer getProxy() {
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
// 检验是否代理访问
private boolean isProxy() {
if (this.proxy == null) {
return false;
} else {
return true;
}
}
}

4.1.3 修改强制代理的代理类

public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;

public GamePlayerProxy(IGamePlayer _gamePlayer) {
this.gamePlayer = _gamePlayer;
}

@Override
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}

@Override
public void killBoss() {
this.gamePlayer.killBoss();
}

@Override
public IGamePlayer getProxy() {
return this;
}
}

4.1.4 修改测试类Client

public class Client {
public static void main(String[] args) {
// 1直接访问真实角色
IGamePlayer player = new GamePlayer("张三");
player.login("zhangsan", "123"); // 输出:请使用指定代理访问
player.killBoss();// 输出:请使用指定代理访问
// 2.直接访问代理类
IGamePlayer player1 = new GamePlayer("张三");
IGamePlayer proxy1 = new GamePlayerProxy(player1);
proxy1.login("zhangsan", "123");// 输出:请使用指定代理访问
proxy1.killBoss();// 输出:请使用指定代理访问
// 3.使用强制代理访问,即找到明确的代理
IGamePlayer player2 = new GamePlayer("张三");
IGamePlayer proxy2 = player2.getProxy();
proxy2.login("zhangsan", "123"); // 输出:登录名为zhangsan的用户张三登录成功
proxy2.killBoss(); // 输出:张三打boss
}
}

5. 动态代理

参考后面的文章​传送门