代理模式
为其他对象提供代理以控制对这个对象的访问(例如火车票代售处代理火车站售票,提供电话预约订票等渠道,但是退票只能在火车站退)
"去掉功能服务,增加额外服务"
各类代理:
1>远程代理:在各个销售店铺设置监控器查看各个位置的销售情况.
2>虚拟代理:网页浏览文章时,因为图片加载不出导致文字也无法显示,可以用一张白色图片代替正在加载的图片先显示,等原图加载完毕后再代替掉白色图片进行显示.
3>保护代理:经过管理员认真才能对帖进行删除,发放等操作,一般用户只能浏览,这种权限控制
4>智能引用代理:火车站代售处
两种机制: 静态代理 动态代理
一、静态代理
代理和被代理对象在代理之前是确定的.他们都实现相同的接口或者继承相同的抽象类.两种机制: 继承 聚合
场景:车对象有一个行驶的方法,增加一个代理,除了有行驶的方法,还要记录行驶的时间.
1>接口:(moveable.java)
package com.zy.proxy;
public interface moveable {
void move();
}
2>被代理类:(Car.java)
package com.zy.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();
}
}
}
3>继承方式代理类:
Car2.java:
package com.zy.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) + "毫秒");
}
}
4>聚合方式代理类:
聚合:一个类中调用另一个对象
package com.zy.proxy;
public class Car3 implements Moveable {
// 利用构造方法把car传进来
public Car3(Car car) {
super();
this.car = car;
}
private Car car;
@Override
public void move() {
// 没用代理是执行头尾记录时间之后进行相减
Long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
car.move();
Long endtime = System.currentTimeMillis();
System.out.println("汽车结束行使.." + (endtime - starttime) + "毫秒");
}
}
5>测试类:
package com.zy.proxy;
public class Test {
public static void main(String[] args) {
// Car car = new Car();
// car.move();
//使用继承方式
// Moveable m = new Car2();
// m.move();
//使用聚合方式
Car car = new Car();
Moveable m = new Car3(car);
m.move();
}
}
二、两种代理的优劣
1>进行代理功能叠加Car4:先进行运行日志的处理,再进行运行时间的处理
Car5:先进行运行时间的处理,再进行运行日志的处理
Car6:先进行运行权限处理,再进行运行日志处理,再进行运行时间处理
Car7:先进行运行权限处理,再进行运行时间处理,再进行运行日志处理
如果是继承的方式,就要依次创建这些子类,则代理类就会无限膨胀下去,所以不合适.
如果是聚合的方式则可以创建不同业务的代理类,只需要将构造方法参数改为代理类所共同实现的Moveable接口和写各自代理类的具体业务代码就可.
例如:
1)CarTimeProxy:时间处理代理类
package com.zy.proxy;
public class CarTimeProxy implements Moveable {
// 代理类与被代理类实现同一个接口,所以构造方法传入接口Moveable
public CarTimeProxy(Moveable m) {
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
// 没用代理是执行头尾记录时间之后进行相减
Long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶...");
m.move();
Long endtime = System.currentTimeMillis();
System.out.println("汽车结束行使.." + (endtime - starttime) + "毫秒");
}
}
2)CarLogProxy:日志处理代理类
package com.zy.proxy;
public class CarLogProxy implements Moveable {
// 代理类与被代理类实现同一个接口,所以构造方法传入接口Moveable
public CarLogProxy(Moveable m) {
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
System.out.println("日志开始...");
m.move();
System.out.println("日志结束...");
}
}
3)Test:测试类
package com.zy.proxy;
public class Test {
public static void main(String[] args) {
Car car = new Car();
// 先进行日志处理后进行时间处理
// CarTimeProxy ctp = new CarTimeProxy(car);
// CarLogProxy clp = new CarLogProxy(ctp);
// clp.move();
// 先进行时间处理后进行日志处理(只需交换代理顺序,而不需要重新写一个子类)
CarLogProxy clp = new CarLogProxy(car);
CarTimeProxy ctp = new CarTimeProxy(clp);
ctp.move();
// 聚合实现相同的接口,代理类之间可以相互传递,是代理推荐的方式
}
}
这里的时间代理类CarTimeProxy和日志代理类CarLogProxy只是针对于汽车Car的代理,那如果来了一辆火车或者自行车,也要实现相同的代理功能逻辑,可不可以针对不同的对象写一个代理类呢?就是能不能写一个TimeProxy类对汽车、火车、自行车进行时间的处理呢?