zoukankan      html  css  js  c++  java
  • Java设计模式之--代理模式学习

    1.代理模式定义

      为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介服务,可以去掉功能服务和增加额外的服务。

      其实按照官方的说法可能不太好理解,代理模式就好比我们生活中买票,一般情况下我们都会去火车站(原对象)买票,但是有的情况下可能我们离火车站比较远不方便去,那我们就会去火车票代售点去(我们的代理对象)买,在这里代售处就是对火车站的一个代理,可以实现卖票的功能,同时呢,代售处也有自己的额外的功能,比如火车票代售处买票需要额外的手续费,火车站能提供的所有服务代售处不是全有,比如代售处不能退票、不能购买学生票,从这里可以看出代理实现了原对象的部分功能外,也有自己额外的处理。

    2.代理模式实现--静态代理

      静态代理:代理和被代理的对象在代理之前都是确定的,他们都是实现了相同的接口或者继承了相同的抽象类。

      举例说明下:汽车有一个move()方法,然后我想通过代理来实现记录汽车运行过程中时间的问题。

      Moveable.java  //定义一个统一的接口,里面定义了一个汽车行驶move()方法

    1 public interface Moveable {
    2     void move();
    3 
    4 }

      Car.java(版本一)   //实现了Moveable接口,实现move方法

    public class Car implements Moveable {
    
        public void move() {
            try {
                Thread.sleep(new Random().nextInt(1000));
                System.out.println("汽车行驶中....");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }

      在这里要实现增加记录汽车运行时间问题,我们是不是可以直接修改Car.java的move方法,如下所示:

    public class Car implements Moveable {
    
        public void move() {
            System.out.println("汽车行驶开始");
            long begin = System.currentTimeMillis();
            try {
                Thread.sleep(new Random().nextInt(1000));
                System.out.println("汽车行驶中....");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long end = System.currentTimeMillis();
            System.out.println("汽车行驶了"+(end-begin)+"毫秒");
        }
    
    }

      这样就实现了记录行驶时间,但是这个得修改Car.java源码,在不修改源码的情况下,怎么做呢,我们就可以通过代理来实现,这里我们将Car.java还原为版本一时候

      Car2.java //新增Car2,继承了Car

     1 public class Car2 extends Car {
     2 
     3     public void move() {
     4         System.out.println("汽车行驶开始");
     5         long begin = System.currentTimeMillis();
     6         super.move();
     7         long end = System.currentTimeMillis();
     8         System.out.println("汽车行驶了"+(end-begin)+"毫秒");
     9     }
    10 
    11 }

       Client.java   //测试类,

    1 public class Client {
    2     public static void main(String[] args) {
    3 //        Car car = new Car();
    4 //        car.move();
    5         Moveable m = new Car2();
    6         m.move();
    7     }
    8 
    9 }

      可以看到运行结果:

    汽车行驶开始
    汽车行驶中....
    汽车行驶了314毫秒

      这样就通过代理实现了记录时间的问题。在super.move();之前和之后我们可以添加新的服务。

      上面我们是通过的继承的方式来实现代理,下面我们换一种方式,用聚合的方式来实现代理模式。

      Car3.java  //新增Car3.java ,采用聚合方式实现

     1 public class Car3 implements Moveable {
     2     private Car car;
     3     
     4     public Car3(Car car){
     5         this.car = car;
     6     }
     7 
     8     public void move() {
     9         System.out.println("汽车行驶开始");
    10         long begin = System.currentTimeMillis();
    11         car.move();
    12         long end = System.currentTimeMillis();
    13         System.out.println("汽车行驶了"+(end-begin)+"毫秒");
    14     }
    15 
    16 }

      修改Client.java来测试,

    1 public class Client {
    2     public static void main(String[] args) {
    3         //采用聚合方式测试代码
    4         Car car = new Car();
    5         Car3 car3 = new Car3(car);
    6         car3.move();
    7     }
    8 
    9 }

      通过运行我们可以得到相同的结果,都可以实现相同的功能。

      但是哪一种方式更好呢,这里我们仅仅是需要增加个记录时间的功能,假如我们需要增加功能有1.时间记录2.日志记录3.权限控制等,可能有的汽车需要先记录时间在记录日志在是权限,即是123方式,可能有的汽车需要321方式,有的汽车只需要1等等,如果我们采用继承的方式的话,每一种方式我们会创建一个新的Java类,这样的话我们的类会无限的庞大,所以推荐使用聚合方式来实现,那聚合方式怎么实现呢,且看下文。

      CarTimeProxy.java  //时间代理类,完成对记录时间的代理功能

     1 public class CarTimeProxy implements Moveable {
     2     private Moveable m;
     3     
     4     public CarTimeProxy(Moveable m){
     5         this.m = m;
     6     }
     7 
     8     public void move() {
     9         System.out.println("汽车行驶开始");
    10         long begin = System.currentTimeMillis();
    11         m.move();
    12         long end = System.currentTimeMillis();
    13         System.out.println("汽车行驶了"+(end-begin)+"毫秒");
    14     }
    15 
    16 }

      CarLogProxy.java  //日志代理类,完成对日志的记录

     1 public class CarLogProxy implements Moveable {
     2     private Moveable m;
     3     
     4     public CarLogProxy(Moveable m){
     5         this.m = m;
     6     }
     7 
     8     public void move() {
     9         System.out.println("汽车日志记录开始");
    10         m.move();
    11         System.out.println("汽车日志记录结束");
    12     }
    13 
    14 }

      修改Client.java来测试,假如我们先记录日志在记录时间

    1 public class Client {
    2     public static void main(String[] args) {
    3         Car car = new Car();
    4         CarTimeProxy time = new CarTimeProxy(car);
    5         CarLogProxy log = new CarLogProxy(time);
    6         log.move();
    7     }
    8 
    9 }

      结果可以看出,先是记录了日志在是时间

    汽车日志记录开始
    汽车行驶开始
    汽车行驶中....
    汽车行驶了586毫秒
    汽车日志记录结束

      这里假如我们需要先记录时间在记录日志,我们仅仅是代码顺序切换下就OK了,

    1 public class Client {
    2     public static void main(String[] args) {
    3         Car car = new Car();
    4         CarLogProxy log = new CarLogProxy(car);
    5         CarTimeProxy time = new CarTimeProxy(log);
    6         time.move();
    7     }
    8 
    9 }
    汽车行驶开始
    汽车日志记录开始
    汽车行驶中....
    汽车日志记录结束
    汽车行驶了192毫秒

      从这里可以看出,聚合的方式比继承更适合代理模式

  • 相关阅读:
    VS缓冲区溢出,未对变量进行检查
    Mutex与Event控制互斥事件的使用详解
    error LNK2019: 无法解析的外部符号
    [转] 兼容IE和Firefox的设为首页和收藏的Javascript代码
    [转]超时时间以到,但尚未从池中获取连接
    Datalist的嵌套使用
    由服务器端向客户端输出脚本
    几个国外的XHTML模板站,DIV+CSS模板下载(转)
    gridview隐藏某一列
    [转]简单谈基于SQL SERVER 分页存储过程的演进
  • 原文地址:https://www.cnblogs.com/lylife/p/4755047.html
Copyright © 2011-2022 走看看