代理模式
学习自 《设计模式之禅(第二版)》
定义
Provide a surrogate or placeholder for another object tocontrol access to it.
为其他对象提供一种代理以控制对这个对象的访问。
角色:
- Subject抽象主题角色
抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。 - RealSubject具体主题角色
也叫做被委托角色、被代理角色。它才是冤大头,是业务逻辑的具体执行者。 - Proxy代理主题角色
也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。
代理模式的优点
- 职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。 - 高扩展性
具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。 - 智能化
代码实现
package design.proxy;
/**
* @author huangqh
* @create 2020/12/8 16:27
* @Notes 代理模式
*/
public class Proxy {
}
/**
* Subject 抽象主题角色
*/
interface IGamePlayer {
public void login(String name, String password);
public void killBoss();
public void upgrade();
}
/**
* RealSubject 具体主题角色
*/
class GamePlayer implements IGamePlayer {
private String name = "";
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login(String name, String password) {
System.out.println(String.format("用户名为%s,密码为%s", name, password));
}
@Override
public void killBoss() {
System.out.println(String.format("%s击杀了boss", this.name));
}
@Override
public void upgrade() {
System.out.println(String.format("%s升级了", this.name));
}
}
/**
* Proxy 代理主题角色
*/
class GamePlayerProxy implements IGamePlayer {
private IGamePlayer iGamePlayer = null;
public GamePlayerProxy(IGamePlayer iGamePlayer) {
this.iGamePlayer = iGamePlayer;
}
@Override
public void login(String name, String password) {
name = name+222;
System.out.println("代理类修改参数");
this.iGamePlayer.login(name, password);
}
@Override
public void killBoss() {
System.out.println("方法执行前");
this.iGamePlayer.killBoss();
}
@Override
public void upgrade() {
this.iGamePlayer.upgrade();
System.out.println("方法执行后");
}
}
class Client{
public static void main(String[] args) {
IGamePlayer player = new GamePlayer("张三");
IGamePlayer proxy = new GamePlayerProxy(player);
proxy.login("张三","123");
proxy.killBoss();
proxy.upgrade();
}
}
普通代理
要求:客户端只能访问代理角色,而不能访问真实角色。
普通代理就是我们要知道代理的存在,也就是类似的GamePlayerProxy这个类的存在,然后才能访问(上列代码简单修改)
package design.proxy;
/**
* @author huangqh
* @create 2020/12/8 17:09
* @Notes 普通代理
*/
public class NormalPorxy {}
interface IGamePlayer {
public void login(String name, String password);
public void killBoss();
public void upgrade();
}
class GamePlayer implements IGamePlayer{
private String name = "";
public GamePlayer(IGamePlayer gamePlayer,String name){
if (gamePlayer==null)
throw new RuntimeException("不能创建真实角色");
else
this.name=name;
}
@Override
public void login(String name, String password) {
System.out.println(String.format("用户名为%s,密码为%s", name, password));
}
@Override
public void killBoss() {
System.out.println(String.format("%s击杀了boss", this.name));
}
@Override
public void upgrade() {
System.out.println(String.format("%s升级了", this.name));
}
}
class GamePlayerProxy implements IGamePlayer {
private IGamePlayer iGamePlayer = null;
public GamePlayerProxy(String name) {
iGamePlayer=new GamePlayer(this,name);
}
@Override
public void login(String name, String password) {
name = name+222;
System.out.println("代理类修改参数");
this.iGamePlayer.login(name, password);
}
@Override
public void killBoss() {
System.out.println("方法执行前");
this.iGamePlayer.killBoss();
}
@Override
public void upgrade() {
this.iGamePlayer.upgrade();
System.out.println("方法执行后");
}
}
class Client{
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayerProxy("张三");
proxy.login("张三","123");
proxy.killBoss();
proxy.upgrade();
}
}
强制代理
强制代理的概念就是要从真实角色查找到代理角色,不允许直接访问真实角色。高层模块只要调用getProxy就可以访问真实角色的所有方法,它根本就不需要产生一个代理出来,代理的管理已经由真实角色自己完成。
强制代理则是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生是由真实角色决定的
package design.proxy;
/**
* @author huangqh
* @create 2020/12/8 17:34
* @Notes 强制代理
*/
public class ForceProxy {
}
/**
* 强制代理接口
*/
interface IGamePlayer {
public void login(String name, String password);
public void killBoss();
public void upgrade();
//获取自己的代理
public IGamePlayer getProxy();
}
/**
* 强制代理真实角色
*/
class GamePlayer implements IGamePlayer {
private String name = "";
private IGamePlayer proxy = null;
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login(String name, String password) {
if (this.isProxy())
System.out.println(String.format("用户名为%s,密码为%s", name, password));
else
System.out.println("请使用代理访问");
}
@Override
public void killBoss() {
if (this.isProxy())
System.out.println(String.format("%s击杀了boss", this.name));
else
System.out.println("请使用代理访问");
}
@Override
public void upgrade() {
if (this.isProxy())
System.out.println(String.format("%s升级了", 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;
return true;
}
}
/**
* 强制代理的代理类
*/
class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer = null;
public GamePlayerProxy(IGamePlayer gamePlayer) {
this.gamePlayer = gamePlayer;
}
@Override
public void login(String name, String password) {
this.gamePlayer.login(name, password);
}
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
@Override
public IGamePlayer getProxy() {
//代理的代理类还没有,返回自己
return this;
}
}
class Client {
public static void main(String[] args) {
GamePlayer g1 = new GamePlayer("张三");
g1.killBoss(); //请使用代理访问
IGamePlayer proxy = new GamePlayerProxy(new GamePlayer("张三"));
proxy.killBoss(); //请使用代理访问
IGamePlayer forceProxy = g1.getProxy();
forceProxy.killBoss(); //张三击杀了boss
}
}
动态代理
package design.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author huangqh
* @create 2020/12/8 18:01
* @Notes 动态代理
*/
public class IHProxy {
}
/**
* Subject 抽象主题角色
*/
interface IGamePlayer {
public void login(String name, String password);
public void killBoss();
public void upgrade();
}
/**
* RealSubject 具体主题角色
*/
class GamePlayer implements IGamePlayer {
private String name = "";
public GamePlayer(String name) {
this.name = name;
}
@Override
public void login(String name, String password) {
System.out.println(String.format("用户名为%s,密码为%s", name, password));
}
@Override
public void killBoss() {
System.out.println(String.format("%s击杀了boss", this.name));
}
@Override
public void upgrade() {
System.out.println(String.format("%s升级了", this.name));
}
}
class GamePlayIH implements InvocationHandler{
//被代理者
Class cls= null;
//被代理的实例
Object obj = null;
//我要代理谁
public GamePlayIH(Object obj){
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(obj, args);
return result;
}
public static void main(String[] args) {
IGamePlayer player = new GamePlayer("张三");
InvocationHandler ih = new GamePlayIH(player);
ClassLoader loader = ih.getClass().getClassLoader();
IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(loader,new Class[]{IGamePlayer.class},ih);
proxy.killBoss();
}
}
通用代理框架
package design.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author huangqh
* @create 2020/12/8 18:18
* @Notes 通用代理 框架
*/
public class absProxy {
}
/**
* 抽象主题
*/
interface Subject{
//业务操作
void doSomething(String str);
}
/**
* 真实主题
*/
class RealSubject implements Subject{
//业务操作
@Override
public void doSomething(String str) {
System.out.println("do something"+str);
}
}
/**
* 动态代理的Handler类
*/
class MyInvocationHandler implements InvocationHandler{
//被代理的对象
private Object target = null;
//通过构造函数传递一个对象
public MyInvocationHandler(Object obj){
this.target=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(this.target,args);
}
}
/**
* 动态代理类
* @param <T>
*/
class DynamicProxy<T>{
public static <T> T newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler v){
//寻找JoinPoint连接点,AOP使用元数据定义
if (true){
//执行一个前置通知
(new BeforeAdvice()).exec();
}
return (T) Proxy.newProxyInstance(loader,interfaces,v);
}
}
/**
* 通知接口
*/
interface IAdvice{
public void exec();
}
/**
* 通知实现
*/
class BeforeAdvice implements IAdvice{
@Override
public void exec() {
System.out.println("我被执行了");
}
}
class Client{
public static void main(String[] args) {
//定义一个主题
Subject subject = new RealSubject();
//定义一个handler
InvocationHandler h = new MyInvocationHandler(subject);
//定义代理主题
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(), h);
//代理行为
proxy.doSomething("Finish");
}
}