结构型

1、代理模式

  • 定义:

    给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

    就好像房东想要出租房子,他让中介帮忙找租客,带看,签合同,房东只需要把房子挂出去表示出租就行了

 

  • 为什么要使用代理模式?

    • 中介隔离作用:

      • 在某些情况下,一个客户不想或者不能去直接访问真实角色,代理角色就能在中间起到一个桥梁连接的作用,前提条件是真实角色委托了代理角色,他们实现相同的接口,有共同的目标。

    • 开闭原则:

      • 代理角色还可以增加额外的功能,这样做我们只需要修改代理角色类而不需要再修改真实角色类,符合代码设计的开闭原则

      • 代理角色类主要负责为真实角色类【预处理消息、过滤消息、把消息转发给真实角色,以及事后对返回结果的处理等

      • 代理角色类本身并不真正实现服务,而是同过调用真实角色类的相关方法,来提供特定的服务。真正的业务功能还是由真实角色类来实现,但是可以在业务功能执行的前后加入一些公共的服务,如:缓存、日志这些功能,在代理角色类中编写,不用打开封装好的真实角色类。

 

2、静态代理

  • 定义:

    静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了

  • 示例一:租房

     

    • Rent(租房事件)

      public interface Rent {
         public void rent();
      }
    • Host(房东:出租房子)

      public class Host implements Rent {
         public void rent() {
             System.out.println("房东出租房子!");
        }
      }
    • HousingAgency(房产中介:代理房东租房子)

      public class HousingAgency implements Rent {
         public Host host;

         ////通过构造方法实现房东与中介的委托代理
         public HousingAgency(Host host) {
             this.host = host;
        }

         public void rent() {
             host.rent();
             signContract();
             seeHouse();
             agencyFee();
        }

         public void signContract() {
             System.out.println("签合同");
        }

         public void seeHouse() {
             System.out.println("中介带看");
        }

         public void agencyFee() {
             System.out.println("中介收取中介费");
        }
      }
    • Tenant(租客:租房子)

      public class Tenant {

         public static void main(String[] args) {

             //实例化一个房东,生成委托对象
             Host host = new Host();
             //房产中介代理房东出租房子
             HousingAgency agency = new HousingAgency(host);
             /*
             租客通过中介租房子,中介也可以实现其他的功能
             输出结果:
            房东出租房子!
                 签合同
                 中介带看
                 中介收取中介费
             */
             agency.rent();

        }
      }
  • 示例二:使用静态代理实现日志功能

     

    • UserService

      public interface UserService {
         public void add();
         public void delete();
         public void update();
         public void query();
      }
    • UserServiceImpl

      public class UserServiceImpl implements UserService {
         public void add() {
             System.out.println("实现了add方法");
        }

         public void delete() {
             System.out.println("实现了delete方法");
        }

         public void update() {
             System.out.println("实现了update方法");
        }

         public void query() {
             System.out.println("实现了query方法");
        }
      }
    • UserServiceProxy

      public class UserServiceProxy implements UserService {

         private UserServiceImpl userService;

         //通过set方法实现userServiceImpl的委托代理
         public void setUserService(UserServiceImpl userService) {
             this.userService = userService;
        }

         public void add() {
             log("add");
             userService.add();
        }

         public void delete() {
             log("delete");
             userService.delete();
        }

         public void update() {
             log("update");
             userService.update();
        }

         public void query() {
             log("query");
             userService.query();
        }

         public void log(String msg) {
             System.out.println("[DEBUG] 调用了" + msg + "方法");
        }
      }
    • Client

      public class Client {
         public static void main(String[] args) {
             
             UserServiceImpl userService = new UserServiceImpl();
             UserServiceProxy proxy = new UserServiceProxy();
             proxy.setUserService(userService);
             
             /*
             输出结果:
            [DEBUG] 调用了add方法
      实现了add方法
             */
             proxy.add();
             /*
             输出结果:
            [DEBUG] 调用了query方法
      实现了query方法
             */
             proxy.query();
        }
      }
  • 优点:

    • 可以使真实角色的操作更加纯粹,不用去关注公共业务

    • 代理角色负责公共业务,分工更加明确

    • 公共业务发生扩展的时候,方便集中管理

  • 缺点:

    • 一个真实角色就会产生一个代理角色,代码量会增加,开发效率降低。

 

3、动态代理

  • 定义:

    动态代理是在程序运行时通过反射机制动态创建的

  • 类别:

    • 基于接口的,JDK动态代理

      • Proxy

      • InvocationHandler

    • 基于类的

      • cglib

    • Java字节码实现

      • javaSsist

  • 示例一:租房

    • Rent

      public interface Rent {
         public void rent();
      }
    • Host

      public class Host implements Rent {
         public void rent() {
             System.out.println("房东出租房子!");
        }
      }
    • ProxyInvocationHandler(代理调用处理程序)

      //这是个可以自动生成代理类的类
      public class ProxyInvocationHandler implements InvocationHandler {

         //被代理的类
         private Rent rent;

         public void setRent(Rent rent) {
             this.rent = rent;
        }

         //生成代理类
         //第一个参数获得类加载器,
         //第二个参数获得被代理类的接口
         //第三个参数是InvocationHandler,因为这个类实现了InvocationHandler,所以可以是它本身
         public Object getProxy() {
             return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
        }

         //处理代理实例,并返回结果
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             //用反射机制来实现动态代理的本质
             Object result = method.invoke(rent, args);
             signContract();
             seeHouse();
             agencyFee();
             return result;
        }

         public void signContract() {
             System.out.println("签合同");
        }

         public void seeHouse() {
             System.out.println("中介带看");
        }

         public void agencyFee() {
             System.out.println("中介收取中介费");
        }
      }
    • Tenant

      public class Tenant {
         public static void main(String[] args) {
           
             Host host = new Host();
             ProxyInvocationHandler proxyIH = new ProxyInvocationHandler();
             
             /*
             每个代理实例都有一个关联的调用处理程序,
             当在代理实例上调用方法时,方法调用将被编码并且分配到其调用处理程序的invoke方法。
             通过调用处理程序来处理我们要调用的接口对象
             */
             proxyIH.setRent(host);
             
             //动态生成代理角色
             Rent proxy = (Rent) proxyIH.getProxy();
             //代理角色去做业务
             proxy.rent();
        }
      }
  • 示例二:使用动态代理实现日志功能

    • UserService

      public interface UserService {
         
         public void add();
         public void delete();
         public void update();
         public void query();
      }
    • UserServiceImpl

      public class UserServiceImpl implements UserService {
         
         public void add() {
             System.out.println("实现了add方法");
        }

         public void delete() {
             System.out.println("实现了delete方法");
        }

         public void update() {
             System.out.println("实现了update方法");
        }

         public void query() {
             System.out.println("实现了query方法");
        }
      }
    • ProxyInvocationHandler

      //这是个可以自动生成代理类的工具类
      public class ProxyInvocationHandler implements InvocationHandler {

         //被代理的类
         private Object target;

         public void setTarget(Object target) {
             this.target = target;
        }

         //生成代理类
         //第一个参数获得类加载器,
         //第二个参数获得被代理类的接口
         //第三个参数是InvocationHandler,因为这个类实现了InvocationHandler,所以可以是它本身
         public Object getProxy() {
             return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }

         //处理代理实例,并返回结果
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             //用反射来获取执行方法的名字
             log(method.getName());
             //用反射机制来实现动态代理的本质
             Object result = method.invoke(target, args);
             return result;
        }

         public void log(String msg) {
             System.out.println("[DEBUG] 执行了" + msg + "方法!");
        }
      }
    • Client

      public class Client {
         public static void main(String[] args) {
             //真实角色
             UserServiceImpl userService = new UserServiceImpl();

             ProxyInvocationHandler proxyIHandler = new ProxyInvocationHandler();
             //设置要代理的对象
             proxyIHandler.setTarget(userService);
             //动态生成代理类
             UserService proxy = (UserService) proxyIHandler.getProxy();
             proxy.delete();
        }
      }
  • 优点:

    • 可以使真实角色的操作更加纯粹,不用去关注公共业务

    • 代理角色负责公共业务,分工更加明确

    • 公共业务发生扩展的时候,方便集中管理

    • 一个动态代理类代理的是一个接口,一般对应的就是一类业务

    • 一个动态代理类可以代理多个实现了同一个接口的类

原文地址:https://www.cnblogs.com/LittleSkinny/p/13697051.html