代理模式的定義
代理模式(Proxy Pattern)是一個使用率非常高的模式,其定義如下:
Provide a surrogate or placeholder for another object to control access to it.(爲其他對象提供一種代理以控制對這個對象的訪問。)
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
//業務邏輯處理
}
}
public class Proxy implements Subject {
private Subject subject = null;
public Proxy() {
this.subject = new Proxy();
}
public Proxy(Object... objects) {
}
@Override
public void request() {
this.before();
this.subject.request();
this.after();
}
private void before() {
}
private void after(){
}
}
代理模式的應用
優點
- 職責清晰
- 高擴展性
- 智能化
使用場景
…………………………(很多)
代理模式的擴展
普通代理
普通代理要求客戶端只能訪問代理角色,而不能訪問真實角色
public interface IGamePlayer {
//登錄遊戲
public void login(String user, String password);
//殺怪
public void kissBoss();
//升級
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;
}
}
@Override
public void login(String user, String password) {
System.out.println("登錄名爲" + user + "的用戶" + this.name + "登錄成功");
}
@Override
public void kissBoss() {
System.out.println(this.name+"在打怪");
}
@Override
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) {
}
}
@Override
public void login(String user, String password) {
this.gamePlayer.login(user, password);
}
@Override
public void kissBoss() {
this.gamePlayer.kissBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
}
public class Client {
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayerProxy("張三");
System.out.println("開始時間是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("結束時間是:2018-09-27 10:00");
}
}
注意 普通代理模式的約束問題,儘量通過團隊內的編程規範類約束,因爲每一個主題類是可被重用的和可維護的,使用技術約束的方式對系統維護是一種非常不利的因素。
強制代理
強制代理卻是要“強制”,你必須通過真實角色查找到代理角色,否則你不能訪問。甭管你是通過代理類還是通過直接new一個主題角色類,都不能訪問,只有通過真實角色指定的代理類纔可以訪問,也就是說由真實角色管理代理角色。
public interface IGamePlayer {
//登錄遊戲
public void login(String user, String password);
//殺怪
public void kissBoss();
//升級
public void upgrade();
//每個人都可以找一下自己的代理
public IGamePlayer getProxy();
}
public class GamePlayer implements IGamePlayer {
private String name = "";
//我的代理是誰
private IGamePlayer proxy = null;
public GamePlayer(String _name) throws Exception {
this.name = _name;
}
//找到自己的代理
@Override
public IGamePlayer getProxy() {
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
@Override
public void login(String user, String password) {
if (this.isProxy()) {
System.out.println("登錄名爲" + user + "的用戶" + this.name + "登錄成功");
} else {
System.out.println("請使用代理訪問");
}
}
@Override
public void kissBoss() {
if (this.isProxy()) {
System.out.println(this.name + "在打怪");
}else{
System.out.println("請使用代理訪問");
}
}
@Override
public void upgrade() {
if (this.isProxy()) {
System.out.println(this.name + "又升了一級!");
}else{
System.out.println("請使用代理訪問");
}
}
//檢查是否是代理訪問
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 kissBoss() {
this.gamePlayer.kissBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
}
//代理的代理暫時還沒有,就是自己
@Override
public IGamePlayer getProxy() {
return this;
}
}
如果直接訪問真實角色
public class Client {
public static void main(String[] args) {
IGamePlayer proxy = new GamePlayer("張三");
System.out.println("開始時間是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("結束時間是:2018-09-27 10:00");
}
}
運行結果就會如下所示
開始時間是:2018-09-26 10:00
請使用代理訪問
請使用代理訪問
請使用代理訪問
結束時間是:2018-09-27 10:00
那麼直接訪問代理呢
public class Client {
public static void main(String[] args) {
IGamePlayer player = new GamePlayer("張三");
IGamePlayer proxy = new GamePlayerProxy(player);
System.out.println("開始時間是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("結束時間是:2018-09-27 10:00");
}
}
結果還是不行
開始時間是:2018-09-26 10:00
請使用代理訪問
請使用代理訪問
請使用代理訪問
結束時間是:2018-09-27 10:00
這是因爲這個代理是你new出來的,不是玩家指定的
public class Client {
public static void main(String[] args) {
IGamePlayer player = new GamePlayer("張三");
IGamePlayer proxy = player.getProxy();
System.out.println("開始時間是:2018-09-26 10:00");
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("結束時間是:2018-09-27 10:00");
}
}
這次終於可以了。
代理是有個性的
一個類可以實現多個接口,完成不同任務的整合。也就是說代理類不僅僅可以實現主題接口,也可以實現其他接口完成不同的任務,而且代理的目的是在目標對象方法的基礎上作增強,這種增強的本質通常就是對目標對象的方法進行攔截和過濾。
例如,增加一個IPorxy接口,作用是用來計算代理的費用。
public interface IPorxy {
//計算費用
public void count();
}
public class GamePlayerProxy implements IGamePlayer,IPorxy {
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 kissBoss() {
this.gamePlayer.kissBoss();
}
@Override
public void upgrade() {
this.gamePlayer.upgrade();
this.count();
}
//代理的代理暫時還沒有,就是自己
@Override
public IGamePlayer getProxy() {
return this;
}
@Override
public void count() {
System.out.println("升級總費用爲 150元");
}
}
代理類不僅僅是可以有自己的運算方法,通常的情況下代理的職責並不一定單一,它可以組合其他的真實角色,也可以實現自己的職責,比如計算費用。代理類可以爲真實角色預處理消息、過濾消息、消息轉發、事後處理消息等功能。當然一個代理類,可以代理多個真實角色,並且真實角色之間可以有耦合關係
動態代理
動態代理是在實現階段不用關心代理誰,而在運行階段才指定代理哪一個對象。相對來說,自己寫代理類的方式就是靜態代理。本章節的核心部分就在動態代理上,現在有一個非常流行的名稱叫做面向橫切面編程,也就是AOP(Aspect Oriented Programming),其核心就是採用了動態代理機制
public class GamePlayIH implements InvocationHandler {
//被代理者
Class cls = null;
//被代理的實例
Object object = null;
//我要代理誰
public GamePlayIH(Object _obj) {
this.object = _obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.object, args);
if (method.getName().equalsIgnoreCase("login")) {
System.out.println("有人在用我的賬號登錄");
}
return result;
}
}
public class Client {
public static void main(String[] args) {
//定義一個癡迷的玩家
IGamePlayer player = new GamePlayer("張三");
//定義一個handler
InvocationHandler handler = new GamePlayIH(player);
//開始遊戲
System.out.println("開始時間是:2018-09-26 10:00");
//獲得類的class loader
ClassLoader c1 = player.getClass().getClassLoader();
//動態產生一個代理類
IGamePlayer proxy = (IGamePlayer) java.lang.reflect.Proxy.newProxyInstance(c1, new Class[]{IGamePlayer.class}, handler);
proxy.login("zhangsan", "password");
proxy.kissBoss();
proxy.upgrade();
System.out.println("結束時間是:2018-09-27 10:00");
}
}
我們看一下一個通用的動態代理代碼
public interface Subject {
//業務操作
public void doSomething(String string);
}
public class RealSubject implements Subject {
@Override
public void doSomething(String string) {
System.out.println("do something --->" + string);
}
}
public class MyInvocationHandler implements InvocationHandler {
//被代理的對象
private Object target = null;
//通過構造函數傳遞一個對象
public MyInvocationHandler(Object target) {
this.target = target;
}
//代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//執行被代理的方法
return method.invoke(this.target,args);
}
}
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) {
//尋找JoinPoint連接點,AOP框架使用源數據定義
if(true){
//執行一個前置通知
(new BeforeAdvice()).exce();
}
return (T) Proxy.newProxyInstance(loader, interfaces, handler);
}
}
public interface IAdvice {
//通知只有一個方法,執行即可
public void exce();
}
public class BeforeAdvice implements IAdvice {
@Override
public void exce() {
System.out.println("前置通知執行了!");
}
}
public class Client {
public static void main(String[] args) {
//定義一個主題
Subject subject = new RealSubject();
//定義一個Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定義主題的代理
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
//代理的行爲
proxy.doSomething("Finish");
}
}
具體業務的動態代理
public class SubjectDynamicProxy extends DynamicProxy {
public static <T> T newProxyInstance(Subject subject) {
ClassLoader classLoader = subject.getClass().getClassLoader();
Class<?>[] classes = subject.getClass().getClasses();
InvocationHandler handler = new MyInvocationHandler(subject);
return newProxyInstance(classLoader, classes, handler);
}
}
場景類更加簡單
public class Client {
public static void main(String[] args) {
//定義一個主題
Subject subject = new RealSubject();
//定義一個Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定義主題的代理
Subject proxy = SubjectDynamicProxy.newProxyInstance(subject);
//代理的行爲
proxy.doSomething("Finish");
}
}