public interface IGamePlayer {
// 登录游戏
void login(String user, String pwd);
// 杀怪
void killBoss();
// 升级
void upgrade();
}
public class GamePalyer implements IGamePlayer {
// 游戏账户名
private String userName;
public GamePalyer(String userName) {
this.userName = userName;
}
@Override
public void login(String user, String pwd) {
System.out.println("登录账号为:" + user + userName + "登录成功");
}
@Override
public void killBoss() {
System.out.println(this.userName + "打boss");
}
@Override
public void upgrade() {
System.out.println("升级了。。。");
}
}
public static void main(String[] args) {
IGamePlayer gamePlayer = new GamePalyer("张三");
System.out.println("游戏开始时间" + "2010年9月4日23:07:30");
gamePlayer.login("zhangsan", "password");
gamePlayer.killBoss();
gamePlayer.upgrade();
System.out.println("游戏结束" + "2019年9月4日23:08:10");
}
游戏开始时间2010年9月4日23:07:30
登录账号为:zhangsan张三登录成功
张三打boss
升级了。。。
游戏结束2019年9月4日23:08:10
结果是我们想要的打游戏的过程,不知道你们有没有这种体验,每天不停地打游戏,腰酸背痛腿抽筋,学习成绩也下降了,白天起不来,晚上睡不着的。如何解决呢,于是产生了一种职业:代练。我也找过代练为我升级。接下来我们修改一下类图。
// 代理类
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer;
public GamePlayerProxy(IGamePlayer gamePlayer) {
this.gamePlayer = gamePlayer;
}
// 代练登录
@Override
public void login(String user, String pwd) {
this.gamePlayer.login(user,pwd);
}
// 代练杀怪
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
// 代练升级
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
}
public static void main(String[] args) {
IGamePlayer gamePlayer = new GamePalyer("张三");
IGamePlayer proxy = new GamePlayerProxy(gamePlayer);
System.out.println("游戏开始时间" + "2010年9月4日23:07:30");
proxy.login("zhangsan", "password");
proxy.killBoss();
proxy.upgrade();
System.out.println("游戏结束" + "2019年9月4日23:08:10");
}
代理模式(Proxy Pattern)是一个使用率非常高的模式,其定义如下:
Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供 一种代理以控制对这个对象的访问。)
- Subject抽象主题角色:抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。
- RealSubject具体主题角色:也叫做被委托角色、被代理角色。它才是冤大头,是业务逻辑的具体执行者。
- Proxy代理主题角色:也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制 委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。
抽象主题类代码如下:
public interface Subject {
//定义一个方法 public void request();
}
真实主题类
public class RealSubject implements Subject {
//实现方法
public void request() {
//业务逻辑处理
}
}
RealSubject是一个正常的业务实现类,代理模式的核心就在代理类上
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 }
}
}
一个代理类可以代理多个被委托者或被代理者,因此一个代理类具体代理哪个真实主题 角色,是由场景类决定的。当然,最简单的情况就是一个主题类和一个代理类,这是最简洁 的代理模式。在通常情况下,一个接口只需要一个代理类就可以了,具体代理哪个实现类由 高层模块来决定,也就是在代理类的构造函数中传递被代理者,例如我们可以在代理类 Proxy中增加如下所示的构造函数。
public Proxy(Subject _subject){
this.subject = _subject;
}
你要代理谁就产生该代理的实例,然后把被代理者传递进来,该模式在实际的项目应用 中比较广泛。
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理 完成一件事务,附带的结果就是编程简洁清晰。
具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱 如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。
以下的动态代理章节中你就会看到代理的智能化
为什么使用代理模式,类似于打游戏找代练,打官司找律师,盖房子找开发商。目的就是减轻自己的负担。
public class GamePlayer implements IGamePlayer {
// 游戏账户名
private String userName;
public GamePlayer(IGamePlayer gamePlayer, String userName) throws Exception {
if (gamePlayer == null) {
throw new Exception("不能创建真实角色");
} else {
this.userName = userName;
}
}
@Override
public void login(String user, String pwd) {
System.out.println("登录账号为:" + user + userName + "登录成功");
}
@Override
public void killBoss() {
System.out.println(this.userName + "打boss");
}
@Override
public void upgrade() {
System.out.println("升级了。。。");
}
}
// 代理类
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer;
public GamePlayerProxy(String userName) {
try {
gamePlayer = new GamePlayer(this, userName);
} catch (Exception e) {
e.printStackTrace();
}
}
// 代练登录
@Override
public void login(String user, String pwd) {
this.gamePlayer.login(user, pwd);
}
// 代练杀怪
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
// 代练升级
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
}
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayerProxy("代理者");
System.out.println("游戏开始");
proxy.login("zhangsan", "password");
proxy.killBoss();
proxy.upgrade();
System.out.println("游戏结束");
}
调用者只需要知道代理类就可以了。不用知道代理了谁。该模式下,屏蔽了真实角色变更对高层模块的影响。真实角色想怎么修改怎么修改。该模式非常适合要求扩展性比较高的场合。
public interface IGamePlayer {
// 登录游戏
void login(String user, String pwd);
// 杀怪
void killBoss();
// 升级
void upgrade();
IGamePlayer getProxy();
}
public class GamePlayer implements IGamePlayer {
// 游戏账户名
private String userName;
private IGamePlayer proxy = null;
public GamePlayer(String userName) {
this.userName = userName;
}
@Override
public void login(String user, String pwd) {
if (this.isProxy()) {
System.out.println("登录账号为:" + user + userName + "登录成功");
} else {
System.out.println("请使用代理");
}
}
@Override
public void killBoss() {
if (this.isProxy()) {
System.out.println(this.userName + "打boss");
} else {
System.out.println("请使用代理");
}
}
@Override
public void upgrade() {
if (this.isProxy()) {
System.out.println("升级了。。。");
} else {
System.out.println("请使用代理");
}
}
@Override
public IGamePlayer getProxy() {
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
private boolean isProxy() {
return this.proxy != null;
}
}
public class GamePlayerProxy implements IGamePlayer {
private IGamePlayer gamePlayer;
public GamePlayerProxy(IGamePlayer gamePlayer) {
this.gamePlayer = gamePlayer;
}
// 代练登录
@Override
public void login(String user, String pwd) {
this.gamePlayer.login(user, pwd);
}
// 代练杀怪
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
// 代练升级
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
@Override
public IGamePlayer getProxy() {
return null;
}
}
// 直接访问真实角色类
IGamePlayer player = new GamePlayer("张飒");
System.out.println("游戏开始");
player.login("zhangsan", "password");
player.killBoss();
player.upgrade();
System.out.println("游戏结束");
游戏开始
请使用代理
请使用代理
请使用代理
游戏结束
// 直接访问代理角色类
IGamePlayer player = new GamePlayer("张飒");
IGamePlayer proxy = new GamePlayerProxy(player);
System.out.println("游戏开始");
proxy.login("zhangsan", "password");
proxy.killBoss();
proxy.upgrade();
System.out.println("游戏结束");
游戏开始
请使用代理
请使用代理
请使用代理
游戏结束
强制代理使用
IGamePlayer player = new GamePlayer("张飒");
IGamePlayer proxy = player.getProxy();
System.out.println("游戏开始");
proxy.login("zhangsan", "password");
proxy.killBoss();
proxy.upgrade();
System.out.println("游戏结束");
游戏开始
登录账号为:zhangsan张飒登录成功
张飒打boss
升级了。。。
游戏结束
public interface IProxy {
void count();
}
// 代理类
public class GamePlayerProxy implements IGamePlayer, IProxy {
IGamePlayer gamePlayer;
public GamePlayerProxy(IGamePlayer gamePlayer) {
this.gamePlayer = gamePlayer;
}
// 代练登录
@Override
public void login(String user, String pwd) {
this.gamePlayer.login(user, pwd);
}
// 代练杀怪
@Override
public void killBoss() {
this.gamePlayer.killBoss();
}
// 代练升级
@Override
public void upgrade() {
this.gamePlayer.upgrade();
this.count();
}
@Override
public void count() {
System.out.println("升级的费用为100元");
}
}
public class GamePlayerIH implements InvocationHandler {
// 被代理者
Class clazz = null;
// 被代理实例
Object object = null;
public GamePlayerIH(Object object) {
// 我要代理谁
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(this.object, args);
}
}
public static void main(String[] args) {
IGamePlayer gamePlayer = new GamePlayer("张三");
InvocationHandler invocationHandler = new GamePlayerIH(gamePlayer);
System.out.println("开始时间是 早上十点");
ClassLoader cl = gamePlayer.getClass().getClassLoader();
IGamePlayer proxy = (IGamePlayer) Proxy.newProxyInstance(cl,new Class[]{IGamePlayer.class},invocationHandler);
proxy.login("张三","pwd");
proxy.upgrade();
proxy.killBoss();
System.out.println("结束时间晚上十点");
}
public class GamePlayerIH implements InvocationHandler {
// 被代理者
Class clazz = null;
// 被代理实例
Object object = null;
public GamePlayerIH(Object object) {
// 我要代理谁
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equalsIgnoreCase("login")){
System.out.println("有人在登录账号");
}
return method.invoke(this.object, args);
}
}
这就是AOP编程。
动态代理实现代理的职责,业务逻辑Subject实现相关逻辑功能。通知Advice从另一个切面切入,最终在Client进行耦合。完成封装任务。
/**
* 抽象主题类
*/
public interface Subject {
void doSomething(String str);
}
/**
* 真实主题类
*/
public class RealSubject implements Subject {
@Override
public void doSomething(String str) {
System.out.println("do Something - - - > " + str);
}
}
/**
* 动态代理类
*/
public class MyInvocationHandler implements InvocationHandler {
// 被代理的实例
private Object object;
public MyInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 执行被代理的方法
return method.invoke(object,args);
}
}
/**
* 动态代理类
* @param
*/
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler) {
if (true) {
// 执行通知
new BeforeAdvice().exec();
}
return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
}
}
下面是实现的简单AOP行为 Advice
/**
* 通知接口
*/
public interface IAdvice {
void exec();
}
/**
* 通知实现类
*/
public class BeforeAdvice implements IAdvice {
@Override
public void exec() {
System.out.println("我是前置通知。。。");
}
}
业务调用
public static void main(String[] args) {
Subject subject = new RealSubject();
InvocationHandler handler = new MyInvocationHandler(subject);
// 此方法生成了一个新的对象,getInterfaces() 查找所有的方法 并让 handler 接管这些所有方法
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);
proxy.doSomething("Finish");
}
动态调用过程如下:
上面代码还有扩展的余地–>封装具体业务的代理类
public class SubjectProxy extends DynamicProxy {
public static <T> T newProxyInstance(Subject subject) {
ClassLoader classLoader = subject.getClass().getClassLoader();
Class<?>[] interfaces = subject.getClass().getInterfaces();
InvocationHandler handler = new MyInvocationHandler(subject);
return newProxyInstance(classLoader, interfaces, handler);
}
}
实际调用会更简单
public static void main(String[] args) {
Subject subject = new RealSubject();
Subject proxy = SubjectProxy.newProxyInstance(subject);
proxy.doSomething("Finish");
}