设计模式(第六式:代理模式)

概念:
  代理模式:为其他对象提供一种代理,以控制对这个对象的访问。
  在代理模式中又分为两种:静态代理和动态代理。代理模式一般默认指静态代理模式。
    静态代理模式:该类型有具体的实现,即就是存在该类型的class文件。
    动态代理模式:及就是只有接口规范,没有具体的实现。也不存在class文件。


实现:
  静态代理:
    定义代理对象接口:

  public interface Author {

            /**
             * 作家具有写作的能力
             */
            void write();
        }


    代理对象实现类

        public class NovelAuthor implements Author {

            @Override
            public void write() {
                System.out.println("我是一个写小说的,现在要准备写小说了");
            }
        }


    代理类实现

        public class ProxyNovelAuthor implements Author {

            private NovelAuthor author;

            public ProxyNovelAuthor() {
                author = new NovelAuthor();
            }

            @Override
            public void write() {
                System.out.println("每次写作之前我都要喝杯咖啡,我刚喝完咖啡");
                author.write();
                System.out.println("写作完成了,签上我的名字送给你。");
            }
        }


  动态代理:
    代理类接口:

public interface Author {

            /**
             * 作家具有写作的能力
             */
            void write();
        }


    代理类Handler,实现InvocationHandler

public class AuthorInvocationHandler implements InvocationHandler {

            private Object obj;

            public AuthorInvocationHandler(Object obj) {
                this.obj = obj;
            }

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                System.out.println("我写作之前,都要喝咖啡。");
                Object result = method.invoke(this.obj, args);
                System.out.println("我写完了,签名并送给你。");
                return result;
            }
        }


测试实现及结果:
  实现:

@Test
    public void proxyTest() {

        ProxyAuthor proxyAuthor = new ProxyAuthor(novelAuthor);
        proxyAuthor.write();

    }

    @Test
    public void dynamicProxyTest_1() {

        AuthorInvocationHandler authorInvocationHandler = new AuthorInvocationHandler((Author) () -> System.out.println("我是现在要准备写小说了"));

        ClassLoader classLoader = authorInvocationHandler.getClass().getClassLoader();
        Class[] cls = new Class[]{Author.class};

        Author author = (Author) Proxy.newProxyInstance(classLoader, cls, authorInvocationHandler);
        author.write();
    }

    @Test
    public void dynamicProxyTest_2() {

        AuthorInvocationHandler authorInvocationHandler = new AuthorInvocationHandler((Author) () -> System.out.println("我是现在要准备写一本工具书..."));

        ClassLoader classLoader = authorInvocationHandler.getClass().getClassLoader();
        Class[] cls = new Class[]{Author.class};

        Author author = (Author) Proxy.newProxyInstance(classLoader, cls, authorInvocationHandler);
        author.write();
    }


  静态代理结果:
    每次写作之前我都要喝杯咖啡,我刚喝完咖啡
    我是一个写小说的,现在要准备写小说了
    写作完成了,签上我的名字送给你。

  动态代理结果1:
    我写作之前,都要喝咖啡。
    我是现在要准备写小说了
    我写完了,签名并送给你。

  动态代理结果2:
    我写作之前,都要喝咖啡。
    我是现在要准备写一本工具书...
    我写完了,签名并送给你。

分析:
  1.静态代理和动态代理的区别:静态代理必须有代理对象的实现类,动态代理则不需要,有也没关系。静态代理类一般和被代理对象类实现同一个代理对象类接口,目的是为了保证有相同的行为。动态代理对象在使用Proxy静态方法是必须要求传入一个接口类型,所以动态代理接口是必须的。其他的区别都不是核心区别。
  2.都方便扩展,但静态代理没有动态代理方便扩展,但目的都是为了解耦合。
  3.静态代理相当于我们利用重写的方式覆盖了原本的方法,动态代理,是利用反射机制实现的调用方法时,添加一些前后操作。
  4.无论是静态代理还是动态代理,对于代理对象来说,都不能直接访问被代理对象的属性,也就是他们只代理了行为,属性并不会被他们代理。
  5.动态代理在没有具体实现类的情况下,没有属性引用,当然动态代理也可以对代理对象进行具体的实现,这样就能用到里面的属性了。
  6.能在不改变原有对象行为的前提下,对原有行为进行适当的改变。
  7.适用场景:远程代理、智能引用代理、保护代理、缓存代理、同步代理、虚拟代理
    a.RMI远程调用
    b.AOP实现也使用了
    ...

经典框架中使用的:
  Spring中大量使用,hibernate、mybatis数据库连接池中使用,以及事务控制的也有使用

posted @ 2019-04-15 10:21  Mario0315  阅读(130)  评论(0编辑  收藏  举报