package com.learn.proxy;import java.util.Random;/*** 产生了坦克这么一个类* 坦克当然是可以移动的,实现了接口,实现了move方法* 我想知道一个方法的运行时间,* 检测一下什么地方是瓶颈,我肯定是在你的方法前前后后加一些代码* 到底运行了多长时间,或者是我给你做一些日志记录,* 如果你没有源码,这个时候你会怎么办,做这个事情之前我们写一个client测试类* @author Leon.Sun**/
public class Tank implements Moveable {/*** 我们现在有一辆坦克,我们想在坦克的move方法前后记录一些内容* 这个时候我想继承一个内容,或者把Tank聚合到我的一个类里,也调用它自己的方法* 这两种方式都挺好,如果我们想要继承来实现,*/@Overridepublic void move() {/*** 记下起始的时间*/// long start = System.currentTimeMillis();       /*** 我们模拟一下坦克正在移动*/System.out.println("Tank Moving.....");/*** 产生一个随机的时间* Random这个类会产生随机数,当你调用它的nextInt方法的时候,* 它会产生这个类以内的随机数,那么现在是产生一万以内的随机数* 睡眠一定的时间,表示坦克休息一段时间,*/try {Thread.sleep(new Random().nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}/*** 记下结束的时间*/// long end = System.currentTimeMillis();/*** 这样我们就知道我们这个方法运行了多长时间*/// System.out.println("time:" + (end-start));}/*** 我们简单写一个实现*/@Overridepublic void stop() {System.out.println("Tank stopping.....");}}
package com.learn.proxy;/*** 如果Moveable里面还有一个方法,Tank必须去实现这个方法* 如果我想知道那个方法的执行时间,* @author Leon.Sun**/
public interface Moveable {void move();void stop();}
package com.learn.proxy;/*** 既然继承我就能够重写它的方法* 假如你父类还有其他的方法,* 用继承把原来的方法前后加一些逻辑,这是一种方式,肯定是没有问题的,* 除了这种方式之外,这个叫继承实现* @author Leon.Sun**/
public class Tank2 extends Tank {/*** 因为你Tank2调用的任何方法,都会调用父类里的方法,* 所以这两种都是代理的实现,不要认为代理的实现只有一种* * 如果我们在move方法上既记录时间又记录日志,用继承的方式* 你可以用Tank3继承Tank2,在这个move方法前面再加一段,前后加上日志,* 我现在想让你先记录时间再记录日志,因为刚才是先记录了日志,最外层的是日志,* 里面是时间* * 这是最开始方法的执行,我包了一层是时间,如果我们想在这个方法外面记录日志的话,* 我们再包一层,所以是一层一层的代理,这是我们最里面的 move方法,* 加一种代理就在里面加一层,加一种代理就包一层,如果我外层的这个叫时间,* 小的椭圆叫时间,外面的叫日志,我们如果用继承的方式,我们就写一个新的Tank3,* 然后从Tank2或者Tank继承都可以,外面包含日志的里面包含时间,* 现在我想把日志包里面,把时间包外面,两个换一换,你自己想一下是不是要重新再建一个类,* 我们现在只有两种组合,如果我们有N种组合的话,那你的实现多少个类才能符合我灵活性的要求* 所以我们用继承的方式来实现代理,他会非常非常的别扭 * 难道你用继承的方式不好实现,难道用聚合的方式就容易实现吗,是这样* */@Overridepublic void move() {long start = System.currentTimeMillis();super.move();long end = System.currentTimeMillis();System.out.println("time:" + (end-start));}
}
package com.learn.proxy;/*** 我让Tank3去实现同样的接口* 现在我们只考虑TankTimeProxy,* 我们现在叫TimeProxy,我叫他TimeProxy就意味着他不仅可以计算Tank的方法* 还可以计算任何的方法的运行时间,我都可以前后加东西来计算时间,* * @author Leon.Sun**/
// public class TankTimeProxy implements Moveable {
public class TimeProxy implements Moveable {/*** 这种叫聚合* 继承和聚合那种方式更好,聚合的意思是一个类里头有另一个类的对象* Tank3拥有另一个Tank对象,然后他另一个坦克的接口,* Tank3就相当于Tank的一个代理,因为你对Tank3调用的任何方法* 都会调用t里面的方法,从这个意义上来讲Tank2也是一个代理* 聚合好,继承不灵活,那这两种方式都可以实现,为什么聚合比继承好* 我们举一个现实中的例子,由于Tank3这种方式比较好,* 它是记录时间的,它是一个代理了坦克这样的一个代理类,* 我就给Tank3改名TankTimeProxy* * 如果我用聚合的方式来实现,首先我要改一个地方,* * */// Tank t;/*** 我完全可以代理Moveable的内容* 这样改过之后我们是不是可以使用TankTimeProxy来代理TankLogProxy* 就是被代理的对象是TankLogProxy,这个当然可以,因为LogProxy也是一个Moveable对象* 而TimeProxy也是一个Moveable对象,所以这个Moveable对象完全可以是LogProxy* * 如果我想完成一个代理,把这个对象当成被代理对象,可以计算Moveable对象的任意一个方法* 前后到底运行了多长时间,有的说为什么会有这样的需求呢,我们现在是记录了Tank里面的运行时间* 如果我现在有个新的类,不叫坦克了,叫Car,汽车中也有各种各样的方法,* stop和move,我想知道Car里面方法到底运行多少时间,这个时候大家想想看,* 你是不是得写一个TimeCarProxy,那有的人说我就写一个CarTimeProxy,* 如果我还有一个类,比如说Animal,里面没有move和stop方法,里面有bite咬人这个方法,* 我想知道他咬了多长时间才松嘴,那我写一个AnimalBiteProxy,那么你有没有发现,* 如果我给你一个系统,里面有100个类,这个100个类运行的时候到底用了多长时间,* 你得写100个代理,你会发现这个代理的类也在无限制的循环下去,所以我就有了这样一段需求,* 无论是给谁做了时间上的代理,不管是给Tank,给Car,还是给Animal做了时间上的代理,* 都是前面加上一个这个,后面加上一个这个,我能不能写一个通用的代理类出来,他可以对任意的对象* 做里面的代理,然后里面的任意的对象都可以加上start和end来计算它们的时间,* 写一个通用的时间上的代理,这个时候我该怎么办,* */Moveable t;// public TankTimeProxy(Moveable t) {public TimeProxy(Moveable t) {super();this.t = t;}/*** 如果我想在方法的前后做一些日志,在方法的开始做一些日志说方法开始了,* 方法的最后记录日志说方法结束了,或者还有新的的应用* 在方法的开始的时候要加一些是事务的控制,在方法结束的时候让方法提交或者回滚* 还有一些是在方法运行之前检查执行这个方法的人有没有这个权限执行,* 有没有运行这个方法的权限,如果有就允许他运行,如果没有就不允许,* 除了你可以记录时间之外,你没准还有其他各种代理* * 就是我写一个before方法之前,然后再写一个after方法之后,* 然后所有的move方法和stop方法,都调用before或者after,* 这样我就简单的把所有的代码都封装到一起了,* 貌似这些代码可以重用了,下面你考虑一个非常非常难的问题,* */@Overridepublic void move() {/*** 只不过我在我的实现里面永远都是调用t的方法* 然后在里面加上我想加的内容* 在前后加上我自己的内容,然后加上一些我自己的方法,*/long start = System.currentTimeMillis();System.out.println("starttime:" + start);t.move();long end = System.currentTimeMillis();System.out.println("time:" + (end-start));}/*** 由于它是一个代理,当然是调用t里面的方法* 这样我就可以把move,stop两个方法的时间全部都给计算出来* 如果你发现一段代码总是在不断的写,那么你一定要考虑好好的把它封装一下,* 因为将来如果你想改这个逻辑的时候,你需要改两个地,方法中你需要改4个地,8个地* 所以最好的方式你是把它写成一个单独的方法*/@Overridepublic void stop() {long start = System.currentTimeMillis();System.out.println("starttime:" + start);t.stop();long end = System.currentTimeMillis();System.out.println("time:" + (end-start));}}
package com.learn.proxy;public class TankLogProxy implements Moveable {// Tank t;Moveable t;public TankLogProxy(Moveable t) {super();this.t = t;}/*** 我们在LogProxy的里面我就不记录时间了,* 这种代理是专门用来做日志的代理* 如果我想做功能上的叠加,现在想让你先做日志然后再记录时间* 如果是继承的方式我在写一个Tank3从Tank2继承* 然后把日志加载Tank2前头,但是如果我想先记录时间再记录日志你该怎么办* 那没办法只能用一个Tank4,然后从坦克2继承,从坦克本身继承,先加上日志再加上时间* 我现在想加一个proxy实现了权限的检查,不仅实现了权限的检查,* 而且还要记录日志还要记录时间,那你说再来继承一个Tank5,我说你把日志和时间给我交换一下* 权限还是给我加载最前面,那你说再加一个Tank6,我说再来proxy,他实现了Transaction,* 还要记录日志还要记录权限,你在怎么办,你说再来Tank8,Tank9,Tank10,* 你会发现这样一种毛病,用继承来实现会无限的继承下去,而且各种各样的代理功能实现叠加的话,* 恐怕这个类的继承的层次会无限制的不停的往下走了,没边没涯了,看不到结尾的地方了,* */@Overridepublic void move() {System.out.println("Tank start.....");t.move();System.out.println("Tank end.....");}@Overridepublic void stop() {}}
package com.learn.proxy;/*** 模拟使用坦克这个类的客户端* 我想知道move方法运行的时间,而不是加上JDK为move运行的时间,* @author Leon.Sun**/
public class Client {public static void main(String[] args) {/*** 如果你不想用这两坦克了,你只要换一个其他实现Moveable接口的类* */// Moveable m = new Tank();/*** 因为Tank2也是一辆坦克,所以他也实现了这个接口*/// Moveable m = new Tank2();/*** 如果我们想要使用聚合的方式我们就是用TankTimeProxy就行了* 那这两种方式都可以实现,为什么聚合比继承好*/// Moveable m = new TankTimeProxy(new Tank());// m.move();// System.out.println("================================================================");// Tank t = new Tank();/*** 然后我们记录一个时间的代理对象* 他就生成了t的代理对象*/// TankTimeProxy ttp = new TankTimeProxy(t);/*** 然后我在TimeProxy外面包装了一层LogProxy,* 因为TimeProxy本身也是Moveable对象,*/// TankLogProxy tlp = new TankLogProxy(ttp);/*** 然后我们让Moveable等于ttp*/// Moveable m = tlp;/*** 调用它来实现他的move方法* 实际运行的是时间代理的这么一个对象* 内部调用的仍然是t的move方法,* 下面我想在时间外面加上一层日志,* */// m.move();//System.out.println("===============================================");//       Tank t = new Tank();       /*** 如果我们想先记录日志* 也就是把前后的包装顺序换一换* */
//      TankLogProxy tlp = new TankLogProxy(t);/*** 这个是先记录日志然后再记录时间* 聚合我虽然也实现了灵活的组合,可是我并不需要按照继承的方式那种类爆炸* 产生很多新的类出来,很多继承的类出来,所以说这是继承的好处,* 其实所有的设计模式前前后后看起来都特别像多态* 但是设计模式一般指的是语义上的而不是语法上的* 聚合确确实实要比继承要好用的多,* 现在我们就用聚合的方式来实现代理,聚合实现的代理有这么一个特点* 聚合会和被代理的对象实现同一个接口* * 这是一个Moveable接口,实现了Moveable可能会有好多好多的额类* 这是我们的Tank,现在我们想实现Tank的代理,我们代理的实现也是实现Moveable接口的,* 这是第一个代理Proxy1,这个代理聚合了被代理的对象,* 就是Proxy里面有一个Tank对象的,严格来讲就是Proxy里面有一个Moveable对象的* 如果我们还有第二个代理,他也实现了Moveable接口,那么在第二个代理里面* Proxy因为是一个实现Moveable被代理的对象,他里面可以装坦克,* 也可以装Proxy1,Proxy1里面也可以装Proxy2,因为里面被代理的对象都是实现了* Moveable接口的对象,所以任何实现Moveable接口的对象,都可以被我这个代理作为被代理的对象* 说明这个东西就灵活多了,我代理之间可以互相的组合,你在代理我再代理,第三个来了一二先排好顺序,我再上* 你会发现灵活度会多了好多,现在大家是不是理解代理模式了,这是静态代理,还不够强大* 类成网了,但是这个类你是可以配置的,你把前后的顺序写在配置文件里,* 我是先日志在时间还是先时间再日志,这样的话你就灵活多了,关键是同一接口,* * 我现在值只讨论TimeProxy,只考虑时间上的代理,我想知道方法执行的时间,* 我想知道一个类的方法的执行时间,* * */
//      TankTimeProxy ttp = new TankTimeProxy(tlp);//      Moveable m = ttp;//        m.move();System.out.println("=============================================================");Tank t = new Tank();       /*** 现在我们只考虑TankTimeProxy,*/TimeProxy ttp = new TimeProxy(t);Moveable m = ttp;m.move();   }}

设计模式之_动态代理_01相关推荐

  1. 设计模式之_动态代理_06

    package com.learn.proxy;public class Client {public static void main(String[] args) throws Exception ...

  2. 设计模式之_动态代理_05

    package com.learn.proxy;public class Client {public static void main(String[] args) {Tank t = new Ta ...

  3. 设计模式之_动态代理_02

    package com.learn.proxy;/*** JDK的那个类就叫Proxy* @author Leon.Sun**/ public class Proxy {/*** 这个方法就是用来产生 ...

  4. 设计模式之_动态代理_03

    我们假设被代理的对象实现了一个接口,不管它实现了什么样的接口,但是它实现了一个接口,用集成也可以实现代理,但是继承不好,所以我们被代理的类要实现一个接口,这个在Spring也是这么要求的,不过Spri ...

  5. 第六周 Java语法总结_设计原则_工厂模式_单例模式_代理模式(静态代理_动态代理)_递归_IO流_网络编程(UDP_TCP)_反射_数据库

    文章目录 20.设计原则 1.工厂模式 2.单例模式 1)饿汉式 2)懒汉式 3.Runtime类 4.代理模式 1)静态代理 2)动态代理 动态代理模板 21.递归 22.IO流 1.File 2. ...

  6. day19_java基础加强_动态代理+注解+类加载器

    一.动态代理 1.1.代理模式     什么是代理模式及其作用?         Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一.         代理模式的定义: ...

  7. android中多态的应用_动态代理原理及在 Android 中的应用

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:trampcr 链接:https://www.jianshu.com/p/492903ab2fae 声明:本文已 ...

  8. 【Spring AOP】静态代理设计模式、Spring 动态代理开发详解、切入点详解(切入点表达式、切入点函数)

    AOP 编程 静态代理设计模式 1. 为什么需要代理设计模式 2. 代理设计模式 名词解释 代理开发的核心要素 静态代理编码 静态代理存在的问题 Spring 动态代理开发 搭建开发环境 Spring ...

  9. 设计模式之----Java动态代理模式

    在Spring中,有很多设计模式被应用,其中不乏代理模式.而代码模式中,就一定少不了动态代理模式.今天就对动态代理模式进行学习记录. 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托 ...

最新文章

  1. QGC开发(一)---编译构建源码
  2. R语言xgboost模型构建:基于prima糖尿病数据集
  3. JavaScript全局函数
  4. screen实现关闭ssh之后继续运行代码
  5. 改变ComboBox控件的高度
  6. php cdi_异步CDI事件
  7. 算法分析-插入排序INSERT_SORT与选择排序SELECT_SORT【线性方法】
  8. 一文了解 Serverless 2021 大事件
  9. 苹果锁定计算机的快捷键,苹果电脑快捷键使用 Mac快捷键大全详细介绍
  10. layui后台管理系统 - 权限树表格
  11. 关于word导出pdf时更新域出错的问题
  12. 网络对时服务器(NTP校时服务器)应用港口信息化系统
  13. 新手必备!最全电路基础知识讲解
  14. RK3288获取摄像头的Sensor ID【原创】
  15. HDU 1998奇数阶魔方
  16. Word安全警告 宏已被禁用解决
  17. 【酷QC++】如何利用酷Q制作一个机器人?
  18. ISO 27001 2022 中文版 范围
  19. ubuntu卸载 mysql
  20. 媒体查询/最大宽度和最小宽度/

热门文章

  1. 通向架构师的道路(第十一天)之Axis2 Web Service(二)
  2. 【PL/SQL】Excel批量往数据库中插入数据:
  3. MongoDB的集群模式--Replica Set
  4. 【robot framework日志】更改log地址(简)
  5. TensorFlow从1到2(四)时尚单品识别和保存、恢复训练数据
  6. 浏览器渲染流水线解析
  7. 深入理解 Angular 变化检测(change detection)
  8. Java+大数据开发——Hadoop集群环境搭建(二)
  9. java----OO的概念和设计原则(转)
  10. linux实例大全学习笔记1