什么是静态代理?
周所周知,常用的23种设计模式中,有一个代理模式(Proxy Pattern)。它的定义如下:
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
那么静态代理又是什么鬼呢?所谓静态就是指,在程序运行前代理类和委托类的对应关系就已经确定了,或者说运行前代理类的字节码文件就有了。
为何用代理模式?
代理模式主要有三个组成部分:
抽象角色:通过接口或者抽象类声明真是角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并且可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
具体的关系我从网上找了一张图,帮助大家理解:
采用代理模式来开发程序的话,我们的业务类只需要关注自己本身的业务逻辑就行了,其他的什么日志,权限控制等辅助功能,就不用再管了,交给代理类去完成就可以了。这样保证了业务类的高复用性。
如何用静态代理?
这里我们使用Java写一个简单的demo,来说明如何使用静态代理。大致需求是一个用户管理的业务类需要添加日志打印功能,如何做呢?方案一,直接将日志打印的代码写到用户管理的业务逻辑实现类里面的方法中;方案二,使用静态代理,将日志打印的代码加到代理类的方法中。在示例代码中,两种方式都有体现。
用户管理接口
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 { 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) { e.printStackTrace(); //System.out.println("error-->>addUser()"); throw new RuntimeException(); } } public void delUser(String userId) { System.out.println("UserManagerImpl.delUser() userId-->>" + userId); } public String findUser(String userId) { System.out.println("UserManagerImpl.findUser() userId-->>" + userId); return "查询成功,找到用户张三"; } public void modifyUser(String userId, String userName) { System.out.println("UserManagerImpl.modifyUser() userId-->>" + userId); } }
用户管理代理类
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("开始添加用户,调用方法:addUser() 用户ID:userId-->>" + userId); userManager.addUser(userId, userName); System.out.println("添加用户成功!"); }catch(Exception e) { e.printStackTrace(); System.out.println("添加用户失败!请联系管理员……"); } } public void delUser(String userId) { userManager.delUser(userId); } public String findUser(String userId) { return userManager.findUser(userId) ; } public void modifyUser(String userId, String userName) { userManager.modifyUser(userId, userName); } }
客户端
public class Client { public static void main(String[] args) { //UserManager userManager = new UserManagerImpl(); UserManager userManager = new UserManagerImplProxy(new UserManagerImpl()); userManager.addUser("0001", "张三"); System.out.println(userManager.findUser("0001")); } }
小结一下:
对于静态代理,有其好处,但是其缺点也是显而易见的。静态代理中的代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口新增加一个方法,除了所有的实现类需要实现这个方法外,所有的代理类也需要实现该方法,这就给代码的维护增加了很大的麻烦。
其次,静态代理模式只服务于一种类型的对象,如果我们要增加一个业务类,那么就必须相应的增加一个代理类,这样如果我们的程序规模非常大,使用静态代理就是一个十分不划算的选择了。那么如何解决这个问题呢?且听下回分解。