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

前言

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

代理模式

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

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

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<args.length; i++) {
			System.out.println(args[i]);
		}
		Object ret = null;
		try {
			//调用目标方法
			ret = method.invoke(targetObject, args);
			System.out.println("success-->>" + method.getName());
		}catch(Exception e) {
			e.printStackTrace();
			System.out.println("error-->>" + method.getName());
			throw e;
		}
		return ret;
	}

}

客户端代码:

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;
	}

}

总结

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

时间: 2024-11-07 17:14:18

DRP总结—在实践中理解代理模式的相关文章

Objective-C中的委托(代理)模式

我个人更喜欢把委托(Delegate)模式称为代理(Proxy)模式.还是那句话,第一次接触代理模式是在Java中接触的,在Java中实现代理模式和接口是少不了的.当时学习Spring的时候用到了接口回调,其实就是实现的委托代理模式.简单的说代理就是把相应的功能交给实现接口的相应的类中来解决.在OC中没有接口该如何实现代理呢?前面的博客中笔者说提了一句,在OC中的协议和Java中的接口极为相似,都是只声明方法而不去实现,方法的实现在OC中交个遵循协议的类,而在Java中方法的实现交给实现接口的类

OC中的代理模式

OC中的代理模式,关于代理模式,如果还有同学不太清楚的话,就自己去补充知识了,这里就不做介绍了,这里只介绍OC中是如何实现代理模式的.这里举一个简单的例子:小孩类,护士类,保姆类,其中小孩类有两个方法:wash和play这里代理对象就是:护士类.保姆类,小孩类是被代理对象.看一下代码:首先看一下小孩类:Children.h[objc]  view plaincopy 1. //   2. //  Children.h   3. //  12_DesignStyle   4. //   5. //

ES6中的代理模式-----Proxy

什么是代理模式 代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式. 所谓的代理者是指一个类别可以作为其它东西的接口.代理者可以作任何东西的接口:网络连接.内存中的大对象.文件或其它昂贵或无法复制的资源. 著名的代理模式例子为引用计数(英语:reference counting)指针对象. 当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少内存用量.典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象.而作用在代理者的运算会转送到原本对象.一

深刻理解代理模式在java中如何优化系统性能

最近参与实习公司的项目迭代,项目中需要实现系统的快速响应和大量数据处理.在不断的学习中获得一点儿心得,先记录下来.慢慢的修改! 关于代理模式的知识和简单应用之前的学习笔记中已经有记录了,可以复习一下.这里主要记录如何使用代理模式来实现延迟加载,进而提升系统系能和反应速度. 使用代理模式实现延迟加载的一个简单实例: 需求:项目中对系统的启动速度做了一定的要求 我们在系统首次加载时,因为不需要实际的数据来构造显示界面,这就为我们实现系统首次加载的快速响应提供了可能.在常规模式下,我们一般会在系统启动

理解Android系统的进程间通信原理(一)----RPC中的代理模式

Android系统中的进程间通信是通过一个轻量级的RPC(Remote Procedure Call远程进程调用)和AIDL(Android Interface Definination Language)规范来生成两个进程之间可以相互访问的代码.其中RPC是以接口方式来实现,客户端与被调用实现之间是通过代理模式来实现的,这些又是以JAVA的RMI和代理模式为理论基础的,若要灵活掌握这个轻量级的解决方案,有必要重新理顺这些基础知识的,这里我们先了解代理模式的相关基础, 有关代理模式的知识,可以用

Objective-C:模拟按钮点击事件理解代理模式

OC中的协议(Protocol)和和.NET中的接口(Interface)类似,简单来讲,就是一系列方法的列表,其中声明的方法可以被任何类实现.不同的是,在.NET中,如果某个类实现了一个接口,就必须实现这个接口中声明的所有方法:但在OC中,可以不实现协议中声明的所有方法,需要用到某些功能,就去实现对应的方法即可. 这种模式一般称为代理模式.在iOS和OS X开发中,Apple采用了大量的代理模式来实现MVC中View(UI控件)和Controller(控制器)的解耦. 监听思想:如果想让某个对

Java中的代理模式

1.什么是代理模式 代理模式:就是为其他对象提供一种代理以控制对这个对象的访问. 代理可以在不改动目标对象的基础上,增加其他额外的功能(扩展功能). 举个例子来说明代理的作用: 一般我们想邀请明星来当我们的代言人,我们并不能直接联系到明星,而是通过其经纪人,来告诉经纪人我们需要和明星进行合作,然后通过经纪人来转达给明星.,明星只需要做好代言工作就好,其他繁琐的事情就交于经纪人就可以.这里的经经纪人就是一个代理对象,明星就是一个目标对象. 用图表示如下: 2.三种代理模式  2.1 静态代理 静态

软件开发常用设计模式—iOS 中的代理模式总结

比如现在有一个人,想要买一张电影票,但是她很忙碌,没时间去买,那怎么办呢?只能说委托给另一个人去买. 此时,需要 person 给 other 发送消息,通知 other 去给她买电影票,而 other 也要反馈消息给 person,此时 other 就是一个代理人,person 委托代理人去办事情(买票).代理人是给委托人代办一些事情的人.具体代理人怎么做的这些事情,委托人不管,委托人只看反馈. 先看代理设计模式的基本原理 #import <Foundation/Foundation.h>

重构-在实践中理解

在老大的推荐下买了Martin Fowler的<Refactoring improving the design of existing code>,其实这本书就是作者重构的经验之谈,随便翻一下,尽管你看的多么仔细,如果你没有在实践中感受到它或者应用到它,其实你很难在需要的时候用上. 昨天服务上线的时候,老大就给我上了一课,首先是一个同事定位到我的一个查询接口超时,于是老大就和我一起看着块超时的代码,看到了这样的代码: B(){ // 在B中发现了代码块BlockA是冗余代码,其实是可以使用一