设计模式学习之代理模式学习

Posted huangliang11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式学习之代理模式学习相关的知识,希望对你有一定的参考价值。

设计模式学习之代理模式学习(一)

      关于设计模式想必学习过Java语言的人都知道吧,当时对其进行深入学习的的人应该不是很多。在我看来设计方面的知识相比于框架应用配置等知识要有意思的多,并且设计模式的对一个程序员的编程思想提升有着很大的帮助。但是设计模式有二十三种,想要全部掌握还是要花点时间的,但如果是只学习常用的几种设计模式还是相对容易的。下面是我学习代理模式的一些心得。

问题引出

     什么是代理模式,为什么要用代理模式。

      现在有一个场景模拟:有一个tank类,他实现了Moveable接口,Moveable接口中有一个move方法,tank类重写move方法。那么现在问题来了,我要想要知道坦克move方法的执行时间怎么办。我想马上就有人会想到在move方法执行前获得一下系统时间,然后在执行后再获得一下系统时间,两个时间相减就能得到move方法的执行时间了。没错这种方法的确能解决刚刚的问题,但是同样带来了另外的问题那就是需要修改源码,这是相当不友好的,在没有源码的前提下还不能实现。那要怎么实现才比较合理了,没错就是代理。讲到这我想我不需要说代理的定义是什么了吧,请看下面代码。

 

 

Tank类的源代码:

 

import java.util.Random;

public class Tank implements Moveable{

    @Override
    public void move() {
        System.out.println("moving......");
        
        try {
            Thread.sleep(new Random().nextInt(10000));
        } catch (InterruptedException e) {
        
            e.printStackTrace();
        }
        
    }

}

 

方法一

    定义一个类继承Tank类并且重写Tank的move方法,在move方法中加入上述逻辑。

 

 * 方法一
 * @author admin
 *
 */
public class Tank2 extends Tank{

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        super.move();
        long end = System.currentTimeMillis();
        System.out.println("time="+(end-start));
        
    }
    
    

}

方法二

   定义一个Tank3类实现了Moveable接口,同时Tank3内有个Moveable类型成员变量。重写move方法并在逻辑代码中间调用Tank的move方法。具体代码如下:

/**
 * 方法二
 * @author admin
 *
 */
public class Tank3 implements Moveable{
    
    private Moveable tank;
    
    public Tank3(Moveable tank) {
        this.tank = tank;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();
        tank.move();
        long end = System.currentTimeMillis();
        System.out.println("time="+(end-start));
        
    }

}

   测试程序:

/**
 * 对于Java代理设计模式的学习
 * 问题:想要知道tank类中的move方法运行的时间
 * 方法一:编写一个类继承tank类,然后在这个类中重写move方法。加上开始时间
 * 和结束时间然后相减。
 * 方法二:编写一个类,里面有一个成员属性是tank类类型,并且实现Moveable
 * 接口。同样重写move方法,并在方法里调用tank中的move方法,并加上相应的
 * 逻辑。(常用,聚合的方式是比继承要好得多,不会出现类爆炸。)
 * @author admin
 *
 */
public class Client {
    public static void main(String[] args) {
        Tank2 tank = new Tank2();
        tank.move();
        
        Tank3 tank1 = new Tank3(new Tank());
        tank1.move();
    }
    

}

 

 

   到此两种实现方法都已给出,那么我们的任务完成了吗,还没有,既然是学习,那么我们就要深入一点。这里给出了两种实现方式,那么哪种实现方式要好了?推荐使用方法二,

我想可能很多人就不服了,为什么啊?

    对于上述问题,我们再来模拟一个场景:现在我们完成计算move运行时间的逻辑,那么问题来了,你的老板要你在move方法执行前后加上一个日志操作。使用方法一就是在创建一个类继承Tank类,并重写move方法加上日志逻辑。方法二是创建一个新的类实现Moveable接口,有个成员变量是Moveable类型成员变量。重写move方法并在日志逻辑代码中间调用成员变量的move方法。这里就有人会有疑问了,感觉没区别啊,都是要创建一个新的类。是的,到现在为止表面上是没有区别。那么现在我们老板又给了我们新的要求,他要我们在实现时间计算的同时加上日志,并且是时间执行在前面,日志执行在后面。使用方法一就是再次创建一个新的类完成两次逻辑。好,老板又改主意了这次他要求日志执行在前,时间计算在后,这时你又要创建一个新的类来完成新的逻辑。哇,好麻烦啊,如果,要求的功能更多,就出现类爆炸了。

   那么方法二是怎么实现的呢?

    假设你现在有了时间逻辑和日志逻辑两个类,现在要完成时间加日志的组合我们只要修改Client程序就行了,不需要再创建新的类了(好舒服)

public class Client {
    public static void main(String[] args) {
        Tank tank1 = new Tank();

        Tank2 tank2 = new Tank2(tank1 );//使用方法二完成的时间计算的类 这里就不给出实现来了
     
        Tank3 tank3 = new Tank3(tank2 );//使用方法二完成的日志逻辑的类 这里就不给出实现来了
        tank3 .move();
    }
    

}

   应为Tank2和Tank3都实现了Movea接口,所以在创建Tank3的时候我们能把Tank2对象传进去。这样就可以把功能组合起来了。如果在创建Tank2时传Tank3就是先日志后时间。各位看都区别了吧,整整少写 了两个类。所以说哪种方式要好,相信大家已经心知肚明了吧。那么到此我们的问题解决了吧。我想说的是还没有,刚刚解决的只是各个功能之间相互组合的问题,但是我们发现每增加一个新的功能我还是要增加一个代理类,这多麻烦啊,我们能不能只生成一个,或者让程序动态的给我们生成呢?当然可以,请关注我后续的博文

设计模式学习之代理模式学习(二)—动态代理

 


以上是关于设计模式学习之代理模式学习的主要内容,如果未能解决你的问题,请参考以下文章

Java学习之动态代理

设计模式学习之代理模式

javascript设计模式学习之六——代理模式

iOS学习之设计模式

Java学习之动态代理

RabbitMQ学习之集群部署