`
goalietang
  • 浏览: 25351 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

浅谈设计模式2 -- 代理模式

阅读更多
        说到代理模式,我想从字面意思,应该是最容易理解的吧。就是本来该我做的事情,我让别人帮我代做了,我不去管别人怎么做,或者说别人做的时候开始会不会多做点什么,结束会不会多做点什么。反正我只知道,我交代做的事情要一件不差的给我代办好。

        举个例子,火车票代购,我事情太多,要找个人代我去买一张火车票。反正我把钱给他了,我的目的就是得到一张票,我管你是偷是抢还是怎样去帮我搞到票。可能你帮我买票之前,会去查一下网上买得到不,找一下有没有人有这方面的推荐...我不管你之前要多干些神马东西。然后你买到票了后,可能你要感谢一下帮你淘到票的人,又可能会记录一下你买票的心得。我也懒得理你,反正到最终你得给我一张我要的火车票。

        以上是代理模式的生活化的一种介绍,在说说在我们程序员这个层面的介绍。那就是:一个角色代表另一个角色来完成某些特定的功能。代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

        先说点题外话,我们要让一个角色帮助(代表)另外一角色来完成一个特定功能(也可以说成执行一个特定方法),其实有几种实现方法,我们来看看最常想到的方法:
        定义一个类SimpleMe,这个类里面有个需要执行的方法doSometing:
public class SimpleMe {
	public void doSometing(){
		System.out.println("do someting........");
	}
}

       再写一个类,继承这个类,重写这个方法,然后呢...
public class OtherProxyMe extends SimpleMe {
	@Override
	public void doSometing() {
		System.out.println("help you to do before");
		super.doSometing();
		System.out.println("help you to do after");
	}
}

        很简单,继承了这个类,重写了这个方法,然后在这个方法里面调用父类的相同方法,最后再调用前后加上自己额外做的事情。可是仔细想想这样的代码会有什么问题呢?首先,滥用了java的继承,单一继承不是这么就浪费掉的。其次继承这种方式依赖性太大。修改父类,第一影响到的就是子类。

        再来看另一种“组合”方式的实现方法,这里我们只写代理类,原始类相同
public class OtherProxyMe {
	private SimpleMe sm;
	public OtherProxyMe(SimpleMe sm){
		this.sm = sm;
	}
	public void doSometing() {
		System.out.println("help you to do before");
		sm.doSometing();
		System.out.println("help you to do after");
	}
}

        这里我们是让这个代理对象拥有原始对象,然后在代理对象执行doSometing()方法的时候顺便执行以下原始对象的doSometing()方法,组合的好处不言而喻,可是以上的代码还是存在问题。首先,代理对象中任何方法都可以执行原始对象的doSomething()方法,我怎么知道是哪个方法在做代理的事情。也可能这个执行原始对象方法的是abc()方法,又可能是def()方法。我们需要规范一下,doSomething()就是doSomething()。原始类要做doSomething(),那么代理类就必须是做doSomething()。而不是abc(),def()。那怎么规范呢?就是让代理对象和原始对象都实现同一个接口。让他们都必须重写doSomething()方法。这样一来,代理对象就名正言顺的使用doSomething()来代理原始对象的doSomething()了。
//定义一个代理接口
public interface SimpleInterface {
	public void doSometing();
}
//原始对象(被代理对象)
public class SimpleMe implements SimpleInterface{
	
	public void doSometing(){
		System.out.println("do someting........");
	}
}
//代理对象
public class OtherProxyMe implements SimpleInterface{
	private SimpleMe sm;
	public OtherProxyMe(SimpleMe sm){
		this.sm = sm;
	}
	public void doSometing() {
		System.out.println("help you to do before");
		sm.doSometing();
		System.out.println("help you to do after");
	}
}

        虽然代理对象比起上面的代码,只是多实现了一个跟原始对象相同的接口,其他的任何地方doumeiy偶改变,但是这样就做了一个很好的规范。使代理方法代理原始方法顺理成章。而且,用组合比用继承好,你稍稍理解一点设计原则都会知道。

        以上,就是是一个简单的静态代理模式的实现,对,你没有听错,你已经学会了一个简单的代理模式了。你可以勇于实践,比如说我执行一个数据库操作,将获取数据库连接和关闭连接资源让代理类来实现,我原始类只focus业务,就是我的数据库操作。又或者,我需要在方法前后加点log,这样的简单代理都能实现。

        再来说说动态代理,很多框架技术用到了动态代理,什么是动态代理呢?

        静态代理由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。而动态代理是在程序运行时,代理类运用反射机制动态创建而成。动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。我们来看看实现:
public class MyHandler implements InvocationHandler {
	//组合一个原始对象
    private Object target;
    //构造方法注入原始对象
    public MyHandler(Object t){
    	this.target = t;
    }
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//执行原始方法之前,执行一些其他方法
		MyProxyMethod.executeBegin(target.getClass().getName() +"."+ method.getName());
		//通过反射执行原始方法
		Object bj = method.invoke(target, args);
		//执行原始方法之后,执行一些其他方法。
		MyProxyMethod.executeEnd(target.getClass().getName() +"."+ method.getName());
		//返回执行结果。
		return bj;
	}
}

       上面就是个基本的动态代理Handler的写法。只需要写这个类,然后有个原始类,我们来看下面的测试方法,如何实现动态代理。
	public static void main(String[] args) {
		//new一个原始对象
		Business a = new BusinessA();
		//将原始对象注入到handler
		MyHandler m = new MyHandler(a);
		//获取代理对象,这里是使用了Proxy的newProxyInstance方法
		Business proxy 
		= (Business) Proxy.newProxyInstance(a.getClass().getClassLoader(), 
				a.getClass().getInterfaces(), m);
		//执行代理方法
		proxy.b1();
		proxy.b2();
	}

        我们在newProxyInstance的时候,传入了三个参数,第一个就是原始对象的ClassLoader,第二个参数是代理对象的接口类型,因为我们知道代理对象和原始对象应该实现同一个接口,这里获取的接口也是原始对象的接口,最后一个参数就是我们自己定义的Handler。这样子,我们就实现了一个动态代理方法。

        顺便说一下,Spring的AOP也是使用InvocationHandler方式来实现的。

        (非常注意点:因为是完全的面向接口编程,所以使用动态代理的时候,所有对象初始化都采用动态绑定方式,用其接口类型来获得实际类型,否则运行时会报错。)
分享到:
评论

相关推荐

    浅谈C#设计模式之代理模式

    代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口.根据代理模式的...

    Java设计模式 版本2

    Java设计模式,目录:前言,UML建模技术,深入浅出UML类图,从招式与内功谈起——设计模式概述,面向对象设计原则,工厂三兄弟之简单工厂模式,工厂三兄弟之工厂方法模式,工厂三兄弟之抽象工厂模式,确保对象的唯一...

    浅谈JAVA设计模式之代理模式

    主要介绍了JAVA设计模式之代理模式的的相关资料,文中代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下

    design-pattern-java.pdf

    实现对象的复用——享元模式(二) 实现对象的复用——享元模式(三) 实现对象的复用——享元模式(四) 实现对象的复用——享元模式(五) 代理模式-Proxy Pattern 设计模式之代理模式(一) 设计模式之代理模式...

    经典:浅谈以太坊智能合约的设计模式与升级方法

    2. 实用设计案例 2.1 控制器合约与数据合约: 1->1 2.2 控制器合约与数据合约: 1->N 2.3 控制器合约与数据合约: N->1 2.4 控制器合约与数据合约: N->N 2.5 总结 3. 升级 3.1 控制器合约升级,数据合约不升级 3.2 控制...

    asp.net知识库

    2分法-通用存储过程分页(top max模式)版本(性能相对之前的not in版本极大提高) 分页存储过程:排序反转分页法 优化后的通用分页存储过程 sql语句 一些Select检索高级用法 SQL server 2005中新增的排序函数及应用 ...

    数据挖掘论文合集-242篇(part2)

    数据仓库与数据挖掘技术浅谈.caj 数据仓库和数据挖掘技术在ERP中的应用.kdh 数据仓库的建设与数据挖掘技术浅析.caj 数据仓库的建设与数据挖掘技术浅析1.caj 数据挖掘 企业决策分析的有效工具.caj 数据挖掘——技术与...

    传智播客扫地僧视频讲义源码

    本教程共分为5个部分,第一部分是C语言提高部分,第二部分为C++基础部分,第三部分为C++进阶部分,第四部分为C、C++及数据结构基础部分,第五部分为C_C++与设计模式基础,内容非常详细. 第一部分 C语言提高部分目录...

    数据挖掘论文合集-242篇(part1)

    数据仓库与数据挖掘技术浅谈.caj 数据仓库和数据挖掘技术在ERP中的应用.kdh 数据仓库的建设与数据挖掘技术浅析.caj 数据仓库的建设与数据挖掘技术浅析1.caj 数据挖掘 企业决策分析的有效工具.caj 数据挖掘——技术与...

    数据挖掘论文合集-242篇(part3)

    数据仓库与数据挖掘技术浅谈.caj 数据仓库和数据挖掘技术在ERP中的应用.kdh 数据仓库的建设与数据挖掘技术浅析.caj 数据仓库的建设与数据挖掘技术浅析1.caj 数据挖掘 企业决策分析的有效工具.caj 数据挖掘——技术与...

    对智能制造的认识(1).doc

    浅谈智能制造 智能制造系统是一种由智能机器和人类专家共同组成的人机一体化系统,它突出了在 制造诸环节中,以一种高度柔性与集成的方式,借助计算机模拟的人类专家的智能活动 ,进行分析、判断、推理、构思和决策...

    数据挖掘在各行业的应用论文

    数据仓库与数据挖掘技术浅谈.caj 用户访问模式数据挖掘的模型与算法研究.caj 数据仓库的建设与数据挖掘技术浅析.caj 分类特征规则的数据挖掘技术.caj 数据挖掘技术的主要方法及其发展方向.caj OLAP和数据挖掘技术在...

Global site tag (gtag.js) - Google Analytics