首页 > 代码库 > 代理模式-你不并知道我的存在

代理模式-你不并知道我的存在

代理模式是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用。它的特征代理类与目标类有同样的接口,并且代理类与目标类之间通常存在关联关系。含有目标类的引用。以至于代理类能够控制目标对象,替它完成它的方法:预处理消息、过滤消息、把消息转发给目标类,以及事后处理消息等。

 

按照代理的创建时期,代理类可以分为两种:


静态代理:

UserManager接口:

public interface UserManager {

         public void addUser(String userId, String userName); //添加用户方法

         public String findUser(String userId); //删除用户方法

}


UserManagerImpl类:

public class UserManagerImpl implements UserManager { 

//用户添加

         public void addUser(String userId, String userName) {            

                   try {
                            System.out.println("用户ID" + userId);                   

                   }catch(Exception e) {

                            e.printStackTrace();                   

                            throw new RuntimeException();

                   }        
         }        

//用户查询 

         public String findUser(String userId) {

                   System.out.println("用户ID" + userId);

                   return "张三";

         }

 

UserManagerImplProxy代理类:

      private UserManager userManager;  //含有目标类对象的引用         

         public UserManagerImplProxy(UserManager userManager) {

                   this.userManager = userManager;
         }         
         public void addUser(String userId, String userName) {

                   try {
                            System.out.println("开始添加-->>添加用户ID" + userId);

                            userManager.addUser(userId, userName);

                            System.out.println("成功添加-->>addUser()");

                   }catch(Exception e) {

                            e.printStackTrace();

                            System.out.println("添加失败-->>addUser()");
                   }        
         } 

public String findUser(String userId) {

                   return null;    //此处不实现,若是实现,其方式同add方法

         }
 


客户端调用:

public class Client {
         public static void main(String[] args) {            
                   UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
                   userManager.addUser("0001", "张三");
         }

}

 

观察以上代码,可以发现每一个代理类只能为一个接口服务(public UserManagerImplProxy(UserManageruserManager))。这样一来需要建立大量的代理类。并且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样。例如,findUser中若是实现,将重复使用System.out.println("开始添加-->>添加用户ID"+ userId); System.out.println("成功添加-->>addUser()"); System.out.println("添加失败-->>addUser()");重复的代码出现多次对于开发人员来说是绝对不允许的,那么该怎么解决这个问题呢?最好的办法那就是通过一个代理类完成全部的代理功能,这就涉及到了动态代理。

 

动态代理:在程序运行时,运用反射机制动态创建而成。

 

代码示例:

UserManager接口:

public interface UserManager { 

         public void addUser(String userId, String userName);
         public String findUser(String userId);

}

真正实现类:

public class UserManagerImpl implements UserManager { 

         public void addUser(String userId, String userName) {            

                   try {
                            System.out.println("用户ID" + userId);          

                   }catch(Exception e) {
                            e.printStackTrace();     
                            throw new RuntimeException();
                   }        
         }

         public String findUser(String userId) {
                   System.out.println("用户ID" + userId);
                   return "张三";

         }

动态代理代理类:

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

动态代理包含一个接口和一个类:

InvocationHandler接口:

 

Public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocatiocHandler h)

throws IllegalArgumentException


返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

 

参数:

        Loader:定义代理类的类加载器

        Class<?>[]interfaces:得到全部的接口      

InvocationHandlerh:得到InvocationHandler接口的子类实例 

 

Proxy类:动态的声明出一个代理对象,为什么样生成出代理呢?这个类必须实现了接口才行。如果这个类没有实现接口,不能生成代理。说白了他就是根据这个接口在内存中建立出一个类。    

 

客户端调用:

public class Client {

         public static void main(String[] args) {

                   LogHandler logHandler = new LogHandler();

                   UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());

                   userManager.addUser("001","猪猪");            

         }

}


总结:

动态代理相对于静态代理来说更加灵活了,为什么呢?例如重载和覆盖,重载属于静态的结构。当定义两个参数不一样的method方法时,我们在调用的时候,需要指定method方法的参数。也就是我们在编译的时候就指定好该调谁了。而覆盖的功能更强,因为它的方法调用不是静态的时候进行绑定,也不是说我写代码编译的时候就指定好我应该调谁。而是在运行的时候决定它是什么类型就调谁。


正常情况下,我们需要创建很多的代理类,如果我还有其他的manager也需要完成这些功能,那么她还需要创建代理类,来完成。动态代理则不用,因为这个proxySubject这个类不需要自己创建,他在内存中创建。所以你压根就不知道代理类的存在,当然代理类的个数,也不需要你关心。


代理模式-你不并知道我的存在