OO模式-Proxy模式静态代理
还依稀记得那个很经典的例子,王五喜欢一个女孩,但是过于害羞,让同伴李四代替自己去送花,最后女孩收到了话,但是猜想一下结果…………1、女孩很高兴,但是不知道到底是谁送的花;2、女孩很高兴李四送给自己花,并对李四有好感;3、女孩知道是王五托李四送给自己的话,心里甚是感激之情。当然咱们的重点并非是猜想最后的结果是什么,而是分析其实本来王五的事情却让李四去帮忙完成,没有直接和女孩交涉,这其实就是一个代理模式。
我们用一个简单的小实例来描述一下,到底何为代理?为什么要用代理?
先举一个小例子,比如我们只写一个简单的增删改查的小功能,需要创建两个类,一个接口类,一个实现类,然后最后是客户端调用,代码如下:
接口类:
public interface UserManager {
// 简单的增删改查方法
public void addUser(String userId, String userName);
public void delUser(String userId);
public void modifyUser(String userId, String userName);
public String findUser(String userId);
}
实现类:
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String userId, String userName) {
// 实现
System.out.println("UserManagerImpl.addUser() userId ==>" + userId);
}
@Override
public void delUser(String userId) {
System.out.println("UserManagerImpl.delUser() userId ==>" + userId);
}
@Override
public void modifyUser(String userId, String userName) {
System.out.println("UserManagerImpl.modifyUser() userId ==>" + userId);
}
@Override
public String findUser(String userId) {
System.out.println("UserManagerImpl.findUser() userId ==>" + userId);
return "huohuo";
}
}
最后客户端调用:
public static void main(String[] args) {
UserManager userManager = new UserManagerImpl();
// 调用添加方法
userManager.addUser("0001", "huohuo");
// 调用查找方法
userManager.findUser("0001");
}
最后的单元测试结果显示:
到这里我们的小测试就完成了,但是看客户端方法,我们的用户直接调用了接口的实现类,这是万万不能的,如果我有大量的方式都来调用我们的实现类,这显然是不合理的,最好的情况还是避免直接交互的方式。现在不考虑这些,我们更换需求,要求在方法执行之前以及执行之后都进行提示,我们该如何去做?
看我们的实现类,其实就是在前后加两句输出代码来表示一下:
@Override
public void addUser(String userId, String userName) {
// 运行之前测试
System.out.println("start ==>addUser() userId ==>" + userId);
try {
// 实现
System.out.println("UserManagerImpl.addUser() userId ==>" + userId);
// 执行成功测试
System.out.println("success ==>addUser()");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
// 执行失败测试
System.out.println("error ==>addUser()");
}
在实现中对每一个方法都增加同样的设置
客户端依旧如此调用,最后的效果图也只是前后多了两条输出语句。代码执行完之后,我们思考一下,如果我有10个方法,我就得写10个同样的设置,最后终于写完了,但是老板突然又想改成别的需求了,比如只需要执行完提示就行,这样的话,就得一一的去每个方法中将不必要的提示去除掉……对于这种情况又该如何是好?所以我们这时候就可以考虑到我们的代理类模式
GoF定义代理模式:为其他对象提供一种代理以控制对这个对象的访问
针对上边的小例子,我们可以直接创建一个代理类来控制客户端对实现类的直接访问,代理类和其目标对象是一样的,所以两者实现共同的接口
新增的代理类:
/**
*
* @ClassName: UserManagerImplProxy
* @Description: 代理类,避免用户直接访问实现,和真实实体实现相同的接口
* @author: HuoYaJing
* @date:2015年11月2日 下午8:46:10
*/
public class UserManagerImplProxy implements UserManager {
private UserManager userManager;
// 创造一个构造方法,来传送目标
public UserManagerImplProxy(UserManager userManager) {
this.userManager = userManager;
}
@Override
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) {
// TODO: handle exception
e.printStackTrace();
// 执行失败测试
System.out.println("error ==>addUser()");
}
}
我们客户端调用的时候,则避免了和实现类的直接访问,通过调用代理类来实现。
publicstatic void main(String[] args) {
// UserManageruserManager = new UserManagerImpl();
// 直接对代理类进行操作(代理类调用目标函数,目标函数调用实现类)
UserManageruserManager=new UserManagerImplProxy(new UserManagerImpl());
// 调用添加方法
userManager.addUser("0001","huohuo");
// 调用查找方法
userManager.findUser("0001");
}
最后的结果肯定也是和之前的结果是一样的,执行成功显示成功,执行失败,显示error提示。这样通过代理类的出现,避免了用户直接访问目标函数,通过代理类的控制来进行访问。只是简单的加了一个代理类,这就是我们说的静态代理,静态代理存在什么问题呢?
- 需要建立大量的代理类,比如我增加方法需要代理类,删除方法也需要代理类……
- 重复的代码会出现在各个角落(和上一点是对应的)