设计模式学习之代理模式学习
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就是先日志后时间。各位看都区别了吧,整整少写 了两个类。所以说哪种方式要好,相信大家已经心知肚明了吧。那么到此我们的问题解决了吧。我想说的是还没有,刚刚解决的只是各个功能之间相互组合的问题,但是我们发现每增加一个新的功能我还是要增加一个代理类,这多麻烦啊,我们能不能只生成一个,或者让程序动态的给我们生成呢?当然可以,请关注我后续的博文
设计模式学习之代理模式学习(二)—动态代理
以上是关于设计模式学习之代理模式学习的主要内容,如果未能解决你的问题,请参考以下文章