一、代理模式的定义
代理模式是一种使用率非常高的模式,也叫做委托模式,当然很多设计模式如状态模式、策略模式、访问者模式本质上都是采用了委托模式,只是在特殊的场合进行使用。它的定义如下:
为其他对象提供一种代理以控制对这个对象的访问。
代理模式中有三种角色:
(1)Subject抽象主题角色
抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。
(2)RealSubject具体主题角色
也叫做被委托角色、被代理角色。它才是业务逻辑的具体执行者。
(3)Proxy代理主题角色
也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色的实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。
二、代理模式的通用代码
抽象主题类
public interface Subject{
//定义一个方法
public void request();
}
真实主题类
public class RealSubject implements Subject{
//实现方法
public void request(){
//业务逻辑处理
}
}
代理类
public class Proxy implements Subject{
//要代理哪个实现类
private Subject subject = null;
//默认被代理者
public Proxy(){
this.subject=new Proxy();
}
//通过构造函数传递代理者
public Proxy(Object ..objects){
}
//实现接口中定义的方法
public void request(){
this.before();
this.subject.request();
this.after();
}
//预处理
private void before(){
//do something
}
//善后处理
private void after(){
//do something
}
}
一个代理类可以代理多个被委托者或被代理者,一个接口只需要一个代理类就可以,具体代理哪个实现类由高层模块来决定,通过构造函数传递对谁进行代理。
public Proxy(Subject subject) {
this.subject = subject;
}
三、代理模块的应用
代理模式的优点
- 职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务。
- 高扩展性
具体主题角色是随时都会发生变化的,只要它实现了接口,不管它如何变化,都逃不脱接口,那我们的代理类完全就可以在不做任何修改的情况下使用。
- 智能化
通过动态代理体现
代理模式的使用场景
代理的目的是在目标对象方法的基础上做增强,而增强的本质是对目标对象的方法进行拦截和过滤。因此只要符合这种需求的情况均可以使用代理模式来实现。例如 Spring AOP(面向切面编程,核心是采用了动态代理机制)。
四、代理模式的扩展
1. 普通代理和强制代理
普通代理:在该模式下,调用者只知代理而不用知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响。
普通代理的抽象主题类:
public interface IGamePlayer {
public void login(String user, String password);
public void killBoss();
public void upgrade();
}
普通代理的真实主题类:
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;
}
}
public void login(String user, String password) {
System.out.println("登录名为" + user + "的用户" + this.name + "登录成功!");
}
public void killBoss() {
System.out.println(this.name + "在打怪!");
}
public void upgrade() {
System.out.println(this.name + "又升了一级!");
}
}
普通代理的代理类:
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(String name) {
try {
gamePlayer = new GamePlayer(this, name);
}catch (Exception e) {
// TODO: handle exception
}
}
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
public void killBoss() {
this.gamePlayer.killBoss();
}
public void upgrade() {
this.gamePlayer.upgrade();
}
}
调用者只需要创建一个代理对象,然后就可以正常进行调用。
public class Client {
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayerProxy("张三");
proxy.login("zhangsan", "admin");
proxy.killBoss();
proxy.upgrade();
}
}
强制代理:在该模式下,由真实角色管理代理角色。只有通过真实角色指定的代理类才可以访问。也就是说,你必须通过真实角色查找到代理角色,否则你将不能访问。
强制代理的抽象主题类:
public interface IGamePlayer {
public void login(String user, String password);
public void killBoss();
public void upgrade();
public IGamePlayer getProxy(); //获取代理
}
强制代理的真实主题类:
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 (isProxy()) {
System.out.println("登录名为" + user + "的用户" + this.name + "登录成功!");
} else {
System.out.println("请使用指定的代理访问");
}
}
@Override
public void killBoss() {
if (isProxy()) {
System.out.println(this.name + "在打怪!");
} else {
System.out.println("请使用指定的代理访问");
}
}
@Override
public void upgrade() {
if (isProxy()) {
System.out.println(this.name + "又升了一级!");
} 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;
}
}
}
强制代理的代理类:
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 void upgrade() {
this.gamePlayer.upgrade();
}
@Override
public IGamePlayer getProxy() {
return this;
}
}
调用者此时不能够再通过直接创建代理对象的方式进行调用了,而是首先创建一个主题对象,然后通过主题对象指定代理,从而创建一个代理对象,然后进行调用。
public class Client {
public static void main(String[] args) {
IGamePlayer player = new GamePlayer("张三");
IGamePlayer proxy = player.getProxy();
proxy.login("zhangsan", "admin");
proxy.killBoss();
proxy.upgrade();
}
}
2. 静态代理和动态代理
静态代理:需要手动实现代理类
动态代理:代理类不需要手动实现,而是自动实现。在实现阶段不需要关心代理谁,而在运行阶段才指定代理哪一个对象。
由于动态代理的内容比较多,后续将单独写一篇博客来介绍相关内容,敬请期待!