欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

DRP总结—在实践中理解代理模式

程序员文章站 2022-04-14 10:17:53
前言 在jdbc访问时,增删改的方法可谓都要进行手动事务处理,所以在每一个方法执行的时候,就都要写事务处理的代码。当敲起代码来不舒服的时候,我们就要想想面向对象的思想,这么多次重复写相同的代码是不对...

前言

在jdbc访问时,增删改的方法可谓都要进行手动事务处理,所以在每一个方法执行的时候,就都要写事务处理的代码。当敲起代码来不舒服的时候,我们就要想想面向对象的思想,这么多次重复写相同的代码是不对的,所以就要进行抽象和封装,于是就有了设计模式。

代理模式

代理模式(proxy):为其他对象提供一种代理,以控制对这个对象的访问。举一个生活中的例子,如果我们买什么东西,我们并不会去工厂直接购买,而是去商场进行选购,这时的商场也就是工厂的代理类。在类的单一职责原则中,一个类应该只做一件事,所以工厂类不应该做销售的工作,商场类也不做制作的工作。

 

DRP总结—在实践中理解代理模式

 

从上图可以看出,代理模式有三种角色:

 

subject:抽象的主题接口,是代理角色和真实角色共同实现的接口,表明在任何使用真实角色的地方,都可以使用代理角色。

 

realsubject:真实角色,代理角色所代表的真实对象,代理所做的一切事情其实都是真实角色做的。

 

proxy:代理角色,代替真实角色和用到真实角色的对象打交道,当然它的工作只有“谈判”,至于具体执行还是要靠真实角色。

 

代理模式有很多适用的地方,常见的远程代理代理模式的运用之一,另外也可以用在较大资源加载时,或者创建时间比较长的对象上面。

 

静态代理

 

静态代理类其实就是程序员编写的,在程序运行前就已经存在的代理类。只需要让代理类和委托类同时实现一个接口,代理类就可以为委托类做事了。

 

代理接口(subject):

 

 

public interface usermanager {

	public void adduser(string userid, string username);
	
}

 

 

真实角色(realsubject):

 

 

public class usermanagerimpl implements usermanager {

	public void adduser(string userid, string username) {
		try {
			system.out.println("usermanagerimpl.adduser() userid-->>" + userid);
			
		}catch(exception e) {
			e.printstacktrace();
			throw new runtimeexception();
		}	
	}

}

 

 

代理角色(proxy):

 

 

public class usermanagerimplproxy implements usermanager {

	private usermanager usermanager;
	
	public usermanagerimplproxy(usermanager usermanager) {
		this.usermanager = usermanager;
	}
	
	public void adduser(string userid, string username) {
		try {
			system.out.println("start-->>adduser() userid-->>" + userid);
			usermanager.adduser(userid, username);
			system.out.println("success-->>adduser()");
		}catch(exception e) {
			e.printstacktrace();
			system.out.println("error-->>adduser()");
		}	
	}

}

 

 

客户端:

 

 

public class client {

	public static void main(string[] args) {
		usermanager usermanager = new usermanagerimplproxy(new usermanagerimpl());
		usermanager.adduser("0001", "张三");
	}

}

 

 

这样一个静态代理模式就完成了,其实从上面代码可以看出,这个代理类是代理realsubject处理了类似日志的东西,但是如果委托类需要代理类做其他事情,那么就得重新创建一个新的代理类,这也就是静态代理的缺点,代理的事情多了,需要写很多代理类,不容易维护。这个时候,我们可以采用动态代理的方式。

 

动态代理

 

java中有一个invocationhandler接口,它采用的就是动态代理的机制,代理类实现这个接口中的newproxyinstance(object targetobject)方法和invoke(object proxy, method method, object[] args)方法,就可以分别实现代理类的实例化和代理事件的执行。动态代理相对于静态代理来说,代理接口、客户端和委托类的代码并没有变化,只是代理类的代码有所改变。

 

代理类(proxy):

 

 

public class loghandler implements invocationhandler {
	
	private object targetobject;
	//创建代理类实例,传入一个对象,无论什么对象
	public object newproxyinstance(object targetobject) {
		this.targetobject = targetobject;
		return proxy.newproxyinstance(targetobject.getclass().getclassloader(),
							   targetobject.getclass().getinterfaces(), this);
	}
	
	//调用代理方法,传入代理类的实例,做完代理类该做的事情后,就会调回委托类的方法
	public object invoke(object proxy, method method, object[] args)
			throws throwable {
		system.out.println("start-->>" + method.getname());
		for (int i=0; i

 

 

客户端代码:

 

 

public class client {
	
	public static void main(string[] args) {
		loghandler loghandler = new loghandler();
		usermanager usermanager = (usermanager)loghandler.newproxyinstance(new usermanagerimpl());
		usermanager.adduser("0001", "张三");
		usermanager.deluser("0001");
	}

}
动态代理相对于静态代理的好处就是,代理类只是在需要的时候创建,而不是上来不管用不用都创建好。

 

 

动态代理封装事务

 

在drp中,动态代理被用在了封装事务,每个访问数据库的方法都执行动态代理类的方法,如果是增删改方法,就为其开启、提交事务,如果有异常就回滚事务;如果是查询的方法,便不执行事务。其实查询最好也放到事务里面,只是这里没有做。

 

 

public class transactionhandler implements invocationhandler {

	private object targetobject;
	
	public object newproxyinstance(object targetobject) {
		this.targetobject = targetobject;
		return proxy.newproxyinstance(targetobject.getclass().getclassloader(),
							   targetobject.getclass().getinterfaces(), this);
	}

	
	public object invoke(object proxy, method method, object[] args)
			throws throwable {
		connection conn = null;
		object ret = null;
		try {
			//从threadlocal中取得connection
			conn = connectionmanager.getconnection();
			if (method.getname().startswith("add") ||
				method.getname().startswith("del") ||
				method.getname().startswith("modify")) {
				//手动控制事务提交
				connectionmanager.begintransaction(conn);
			}	
			//调用目标对象的业务逻辑方法
			ret = method.invoke(targetobject, args);
			if (!conn.getautocommit()) {
				//提交事务
				connectionmanager.committransaction(conn);
			}
		}catch(applicationexception e) {
			//回滚事务
			connectionmanager.rollbacktransaction(conn);
			throw e;
		}catch(exception e) {
			e.printstacktrace();
			if (e instanceof invocationtargetexception) {
				invocationtargetexception ete = (invocationtargetexception)e;
				throw ete.gettargetexception();
			}
			//回滚事务
			connectionmanager.rollbacktransaction(conn);
			throw new applicationexception("操作失败!");
		}finally {
			connectionmanager.closeconnection();
		}
		return ret;
	}

}

 

 

总结

 

不管是动态代理还是静态代理,总是会为委托类建立各种代理类,类多了自然也不容易管理,这也是代理模式的缺点之一。动态代理和静态代理的区别,在于二者执行过程中,代理类的创建时间不同,静态代理是程序运行前就要把类写好,动态代理是在执行过程中动态创建。这里的动态代理的执行,很像是面向切面的,它在程序执行过程中,横向切入进去进行检查,如果是增删改的方法,则为其执行手动事务的处理。

;>