代理模式:
为其他对象提供一种代理以控制对这个对象的访问,代理对象起到了中介作用,可以去掉功能服务或者额外的服务。
以火车站买票为例子:
火车票代售处是火车站的代理,代售处可能不止可以卖火车票,还可以卖飞机票,但是不支持火车票退票功能,因此代售处起到了中介作用,
可以去掉功能服务或者额外的服务。
常见代理模式:远程代理,虚拟代理,保护代理,智能引用代理。
智能引用代理
两种实现方式:静态代理,动态代理。
静态代理:代理和被代理对象在代理之前是确定的。他们都实现相同的接口或者继承相同的抽象类。
静态代理分继承方式和聚合方式两种实现。
实例:
通过代理,实现汽车行驶的方法,同时记录汽车的行驶时间。
普通不使用设计模式实现方式:
第一步:行驶接口:
package com.Proxy; public interface Moveable { void move(); }
第二步:实现汽车类:汽车类中实现行驶方法,里面记录行驶时间。
package com.Proxy; import java.util.Random; public class Car implements Moveable { @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽车开始形式...."); //实现开车 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中...."); } catch (InterruptedException e) { e.printStackTrace(); } long endtime=System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒"); } }
第三步:测试:
package com.Proxy; public class Client { /* * 测试类 * */ public static void main(String[] args) { Car car=new Car(); car.move(); } }
运行结果:
汽车开始形式....
汽车行驶中....
汽车结束行驶...汽车形式时间:602毫秒
修改为静态代理:
第一种静态代理:以继承的方式代理:
Car类修改为只有行驶方式:
package com.Proxy; import java.util.Random; public class Car implements Moveable { @Override public void move() { //实现开车 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽车行驶中...."); } catch (InterruptedException e) { e.printStackTrace(); } } }
新建Car2类继承Car类,通过super.方法()方式调用父类的方法,实现静态代理。
同时在这个方法里面实现记录开车时间。
package com.Proxy; public class Car2 extends Car { @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽车开始形式...."); super.move(); long endtime=System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒"); } }
测试:
package com.Proxy; public class Client { /* * 测试类 * */ public static void main(String[] args) { Moveable m=new Car2(); m.move(); } }
效果:
汽车开始形式....
汽车行驶中....
汽车结束行驶...汽车形式时间:497毫秒
第二种静态代理:以聚合的方式实现代理:
聚合的方式其实就是在一个类中调用另一个类的对象,一般在构造方法里面把另一个类的对象传进来。
实现:
Car类和接口同上。
新建Car3继承接口,同时在构造方法里面把Car类对象传进来。
package com.Proxy; /* * 以聚合方式代理:一个类中调用另一个类的对象 * */ public class Car3 implements Moveable{ private Car car; public Car3(Car car) { this.car=car; } @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽车开始形式...."); car.move(); long endtime=System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒"); } }
测试:
package com.Proxy; public class Client { /* * 测试类 * */ public static void main(String[] args) { // 不使用代理方式 // Car car=new Car(); // car.move(); // //以继承方式实现代理 // Moveable m=new Car2(); // m.move(); //以聚合方式实现代理 Car car=new Car(); Moveable m2=new Car3(car); m2.move(); } }
效果:
汽车开始形式....
汽车行驶中....
汽车结束行驶...汽车形式时间:200毫秒
继承方式和聚合方式两种比较:
如果此时代理类除了要实现汽车行驶方法,还可能需要实现其他功能的代理,比如权限管理,日志处理。
1,对于继承方式的代理来说:
如果我想先记录汽车行驶时间,在记录日志,需要新建一个代理类。
假如此时我又想先记录日志,再记录汽车行驶时间,此时又得新建一个代理类。
所以使用继承方式不合适。
2,使用聚合方式就没这个问题,代码验证:
这里要实现两种方式:即先记录时间,再记录日志;和先记录日志,再记录时间。
实现的方式就是,各个功能分别建立一个代理类,并且代理类的构造方法不仅能够传递被代理类(Car),也能能够把其他的代理类传递进来,
以此实现上述的两种不同的实现方式。
代码:
新建一个时间记录代理类:
为了可以让构造方法里面的参数既可以是被代理的Car类,也可以是代理类。
package com.Proxy; //时间代理 public class CarTimeProxy implements Moveable{ private Moveable m; public CarTimeProxy(Moveable m) { this.m=m; } @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽车开始形式...."); m.move(); long endtime=System.currentTimeMillis(); System.out.println("汽车结束行驶...汽车形式时间:"+(endtime-starttime)+"毫秒"); } }
新建一个日志记录代理类:
package com.Proxy; //日志代理 public class CarLogProxy implements Moveable{ private Moveable m; public CarLogProxy(Moveable m) { this.m=m; } @Override public void move() { System.out.println("日志开始...."); m.move(); System.out.println("日志结束...."); } }
新建测试类:测试类分别通过两个代理类顺序不同,把相关代理类传递给另一个代理类调用:
package com.Proxy; //聚合的代理模式,各个代理类直接可以互相传递,组合, public class Clien2 { public static void main(String[] args) { Car car=new Car(); // //先记录日志,再记录时间 // CarTimeProxy ctp=new CarTimeProxy(car); // CarLogProxy clp=new CarLogProxy(ctp);//把时间代理传进去,这时候日志代理类代理了时间代理类 // clp.move(); //先记录日志,再记录日志,只需要调整一下代理类的顺序 CarLogProxy clp2=new CarLogProxy(car); CarTimeProxy ctp2=new CarTimeProxy(clp2);//把时间代理传进去,这时候日志代理类代理了时间代理类 ctp2.move(); } }