`

代理模式——动态代理

阅读更多

设计模式之禅学习——动态代理

一、代理模式就是为其他对象提供一种代理,来控制对这个对象的访问,代理模式的好处有很多,最常见的AOP,原理就是使用了代理模式的动态代理。下面学习书中游戏者的例子。就是有一个玩游戏的人,自己不想升级,来找代理者,帮他升级的故事。

1、游戏者接口:

package com.wang.proxyPattern.example;

/**
 * 游戏者接口
 * @author HeJW
 *
 */
public interface IGamePlayer {

	public void login(String user, String password);
	public void killBoss();
	public void upgrade();
}

 2、真实的游戏者:

package com.wang.proxyPattern.example;

/**
 * 游戏者
 * @author HeJW
 *
 */
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 + "在打怪");
	}

	@Override
	public void upgrade() {
		System.out.println(this.name + "又升一级");
	}

}

 3、游戏代理者:

package com.wang.proxyPattern.example;

/**
 * 游戏代练者
 * @author HeJW
 *
 */
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();
	}

}

 4、常见类:

package com.wang.proxyPattern.example;

import java.util.Date;

public class App2 {
	
	public static void main(String[] args) {
		
		IGamePlayer player = new GamePlayer("张三");
		IGamePlayer proxy = new GamePlayerProxy(player);
		System.out.println("开始时间是:" + new Date());
		proxy.login("zhangSan", "password");
		proxy.killBoss();
		proxy.upgrade();
		System.out.println("结束时间是:" + new Date());
	}
}

 当然,这是最简单的一种代理模式,代理模式还包括普通代理和强制代理。

 

二、普通代理,普通代理就是限制客户端创建对象,必须构建一个代理对象,使用这个代理对象完成业务。

1、普通代理的游戏者

package com.wang.proxyPattern.develop.common;

import com.wang.proxyPattern.example.IGamePlayer;

/**
 * 普通代理的游戏者 
 * @author HeJW
 *
 */
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 + "在打怪");
	}

	@Override
	public void upgrade() {
		System.out.println(this.name + "又升一级");
	}

}

 2、普通代理的代理者

package com.wang.proxyPattern.develop.common;

import com.wang.proxyPattern.example.IGamePlayer;

/**
 * 普通代理的代理者
 * @author HeJW
 *
 */
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();
	}

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

}

 3、客户端:

package com.wang.proxyPattern.develop.common;

import java.util.Date;

import com.wang.proxyPattern.example.IGamePlayer;

public class App {
	
	public static void main(String[] args) {
		IGamePlayer proxy = new GamePlayerProxy("张三");
		System.out.println("开始时间是:" + new Date());
		proxy.login("zhangSan", "password");
		proxy.killBoss();
		proxy.upgrade();
		System.out.println("结束时间是:" + new Date());

//		//通过约定,禁止这么用
//		try {
//			GamePlayer player = new GamePlayer(proxy, "张三");
//			System.out.println("开始时间是:" + new Date());
//			player.login("zhangSan", "password");
//			player.killBoss();
//			player.upgrade();
//			System.out.println("结束时间是:" + new Date());
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
	}
}

 当然了,在代码的实现中,客户端不一定非要new一个代理者对象,但是,可以通过约定,进行限制。

 

三、强制代理,强制代理就是必须通过真实角色找到这个真实角色的代理类,再用这个代理类完成业务。

1、强制代理接口类:

package com.wang.proxyPattern.develop.compel;

/**
 * 强制代理的接口类
 * @author HeJW
 *
 */
public interface IGamePlayer {

	public void login(String user, String password);
	public void killBoss();
	public void upgrade();	

	//每个人都可以找到自己的代理类
	public IGamePlayer getProxy();
}

 2、强制代理的真实角色:

package com.wang.proxyPattern.develop.compel;

/**
 * 强制代理的真是角色
 * @author HeJW
 *
 */
public class GamePlayer implements IGamePlayer {

	private String name = null;
	
	//代理类
	private IGamePlayer proxy = null;
	
	public GamePlayer(String name) {
		this.name = name;
	}
	
	@Override
	public IGamePlayer getProxy() {
		this.proxy = new GamePlayerProxy(this);
		return 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 killBoss() {
		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;
		} 
	}

	

}

3、强制代理的代理类:

package com.wang.proxyPattern.develop.compel;

/**
 * 强制代理的代理类
 * @author HeJW
 *
 */
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 null;
	}

}

  4、在客户端必须像如下形式完成客户端:

package com.wang.proxyPattern.develop.compel;

import java.util.Date;

public class App3 {
	
	public static void main(String[] args) {
		
		IGamePlayer player = new GamePlayer("张三");
		IGamePlayer proxy = player.getProxy();
		System.out.println("开始时间是:" + new Date());
		proxy.login("zhangSan", "password");
		proxy.killBoss();
		proxy.upgrade();
		System.out.println("结束时间是:" + new Date());
	}
}	

 如果用一下两种形式的客户端,就会打印出”请使用指定代理访问“

package com.wang.proxyPattern.develop.compel;

import java.util.Date;

public class App1 {
	
	public static void main(String[] args) {
		IGamePlayer player = new GamePlayer("张三");
		System.out.println("开始时间是:" + new Date());
		player.login("zhangSan", "password");
		player.killBoss();
		player.upgrade();
		System.out.println("结束时间是:" + new Date());
	}
}	

第二种:

package com.wang.proxyPattern.develop.compel;

import java.util.Date;

public class App2 {
	
	public static void main(String[] args) {
		
		IGamePlayer player = new GamePlayer("张三");
		IGamePlayer proxy = new GamePlayerProxy(player);
		System.out.println("开始时间是:" + new Date());
		proxy.login("zhangSan", "password");
		proxy.killBoss();
		proxy.upgrade();
		System.out.println("结束时间是:" + new Date());
	}
}	

  

四、动态代理,动态代理之所以叫动态,是因为它在实现阶段不用关心代理谁,而在运行阶段才指定代理那个对象,要完成动态代理就要实现一个JDK提供的接口:InvocationHandler(动态代理接口)

(一下用到的代码和上面的没有关系)

1、首先先定义一个抽象主题接口:

package com.wang.proxyPattern.handler;

/**
 * 抽象主题
 * @author HeJW
 *
 */
public interface Subject {
	
	//业务操作
	public void doSomething(String str);
}

 2、真实主题:

package com.wang.proxyPattern.handler;

/**
 * 真实主题类
 * @author HeJW
 *
 */
public class RealSubject implements Subject {

	@Override
	public void doSomething(String str) {
		System.out.println("do something ------" + str);
	}

}

 3、动态代理的Handler类:

package com.wang.proxyPattern.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理的Handler
 * @author HeJW
 *
 */
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);
	}

}

 4、动态代理类:

package com.wang.proxyPattern.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 动态代理类
 * @author HeJW
 *
 * @param <T>
 */
public class DynamicProxy<T> {
	
	public static <T> T newProxyInstance( ClassLoader loader, Class<?>[] interfaces,
			InvocationHandler h){
		
		if(true){
			//执行一个前置通知
			(new BeforAdvice()).exec();
		}
		return (T) Proxy.newProxyInstance(loader, interfaces, h);
		
	}
}

 5、上面用到的通知接口:

package com.wang.proxyPattern.handler;

/**
 * 通知接口
 * @author HeJW
 *
 */
public interface IAdvice {
	
	public void exec();
}

 实现:

package com.wang.proxyPattern.handler;

/**
 * 通知的实现类
 * @author HeJW
 *
 */
public class BeforAdvice implements IAdvice {

	@Override
	public void exec() {
		System.out.println("前置通知");
	}

}

 6、动态代理的使用:

package com.wang.proxyPattern.handler;

import java.lang.reflect.InvocationHandler;

public class App1 {
	
	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(" hello handler ");
		
	}
}

 7、进一步实现具体业务的动态代理:

package com.wang.proxyPattern.handler;

import java.lang.reflect.InvocationHandler;

/**
 * 具体业务的动态代理
 * @author HeJW
 *
 */
@SuppressWarnings("rawtypes")
public class SubjectDynamicProxy extends DynamicProxy {
	
	public static <T> T newProxyInstance( Subject subject ){
		
		//获得ClassLoader
		ClassLoader loader = subject.getClass().getClassLoader();
		
		//获得接口数组
		Class<?>[] classes = subject.getClass().getInterfaces();
		
		//获得handler 
		InvocationHandler handler = new MyInvocationHandler(subject);
		
		return newProxyInstance(loader, classes, handler);
	}
}

 8、客户端使用:

package com.wang.proxyPattern.handler;

public class App2 {
	
	public static void main(String[] args) {
		
		Subject subject = new RealSubject();
		Subject proxy = SubjectDynamicProxy.newProxyInstance(subject);
		proxy.doSomething(" hello ");
	}
}

 

 

动态代理是个好东西,有很多框架都用到动态代理,我们在用代理模式的时候,也可以把这些框架直接拿来使用,很方便。还记得第一次见到动态代理的时候,那时候感觉”哇。。这都什么东东,,,这么神奇呢,,我肯定看不懂,,算了不看了,,,“   好多次都这样,,到现在也还是不理解动态代理到底是什么,怎么实现的动态代理,但是还是硬着头皮看了,相信会慢慢理解的。。。。。

 

1
0
分享到:
评论

相关推荐

    Java设计模式——代理设计模式(静态代理和动态代理)

    在Java编程中,设计模式是一种解决常见问题的模板或最佳实践,它可以帮助开发者编写更加灵活、可维护和可扩展的代码。代理设计模式是其中的一种,它的主要作用是在...在实际开发中,应根据项目需求选择合适的代理模式。

    设计模式实现——代理模式

    **设计模式实现——代理模式** 在软件工程中,设计模式是一种通用可重用的解决方案,它描述了在特定上下文中经常出现的问题以及该问题的解决方案。代理模式是设计模式的一种,它提供了一种对目标对象的间接访问方式...

    设计模式——代理模式

    此外,代理模式还可以利用动态代理技术,例如Java中的`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口,这使得在运行时动态创建代理对象成为可能,而无需预先知道所有可能的代理类。...

    设计模式——GFour

    结构型模式则关注如何将不同组件组合成更复杂的结构,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。这些模式帮助我们处理类与类之间的关系,使得代码结构更加清晰,增强了系统的...

    设计模式——装饰模式

    装饰模式是一种设计模式...通过阅读和理解《设计模式:可复用面向对象软件的基础》等经典书籍,以及像博客“设计模式——装饰模式”这样的在线资源,我们可以深入掌握并灵活运用装饰模式,提高代码的可维护性和扩展性。

    Java与模式——源码

    《Java与模式——源码》这个主题涉及到的是Java编程语言中的设计模式应用,以及如何通过源代码来理解和学习这些模式。设计模式是软件工程中的一种最佳实践,它们是解决常见问题的经验总结,使得代码更易读、易维护、...

    设计模式——刘伟

    6. **代理模式**:为其他对象提供一种代理以控制对该对象的访问。代理可以在目标对象前增加额外的功能,如缓存、日志记录、事务控制等。 7. **建造者模式**:将一个复杂对象的构建与其表示分离,使得同样的构建过程...

    Java 代理 代理模式 静态代理与动态代理 常见的动态代理实现 .md

    代理模式可以进一步细分为静态代理和动态代理。 - **静态代理**:在程序编译时就已经确定代理类的具体实现方式。这意味着每次需要代理不同的操作时,都需要修改代理类的代码,这违反了软件工程中的开闭原则。 - **...

    浅析Java设计模式【3】——代理.pdf

    ### 浅析Java设计模式【3】——代理 #### 一、代理模式概述 代理模式是一种行为型设计模式,主要用于在客户端与目标对象之间起到一个中介的作用,通过代理对象来控制对目标对象的访问。代理模式的核心在于它可以...

    JAVA设计模式(代理模式)

    **Java设计模式——代理模式详解** 代理模式是软件设计模式中的一个重要组成部分,它在Java编程中扮演着举足轻重的角色。代理模式的核心思想是为一个对象提供一个替身,这个替身即代理对象,代理对象可以控制对原...

    基于Java的设计模式-代理模式demo的实现(高分课设)

    基于Java的设计模式——代理模式demo的实现(高分课设)个人经导师指导并认可通过的98分大作业设计项目,适用人群:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业或毕业设计,作为“参考资料”使用...

    设计模式——原版的设计模式

    代理模式为其他对象提供一种代理以控制对这个对象的访问;组合模式将对象组合成树形结构以表示“部分-整体”的层次结构。 3. **行为型模式**:这类模式涉及对象之间的责任分配。命令模式将请求封装为一个对象,从而...

    实例_ Java中的代理模式(csdn)————程序.pdf

    在Java中,代理模式有静态代理和动态代理两种实现方式。 ### 静态代理 静态代理是最基础的形式,它需要我们为每一个被代理的对象创建一个对应的代理类。在静态代理中,代理类通常会实现与被代理类相同的接口,以...

    详解ES6中的代理模式——Proxy

    什么是代理模式 代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。 所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、内存中的大对象、文件或其它昂贵或无法...

    经典的EJB模式——门面模式

    在实际应用中,门面模式可以结合其他设计模式一起使用,例如工厂模式用于创建EJB实例,代理模式用于提供额外的控制层等,以进一步优化系统的结构和性能。总的来说,门面模式是EJB开发中不可或缺的一个工具,它有效地...

    java 设计模式 静态代理模式

    //代理模式内部引用了真实角色 public void requst() { this.preRequest(); //在真实角色操作之前所附加的操作 if(null == realsubject) { realsubject = new ReallSubject(); } realsubject.requst(); // ...

    iOS设计模式——委托(delegate)例子

    在iOS开发中,设计模式是实现高效、可维护和可扩展代码的关键元素。本文将重点关注“委托”(Delegate)设计模式,这是一种常见的模式,用于在对象之间建立通信和协调行为。通过实现委托,一个对象(委托者)可以...

Global site tag (gtag.js) - Google Analytics