运用场景:
当需要调用到某个方法,而又需要在该方法执行之前或之后再执行其他的逻辑时,就可以用到代理的技术。
分类:
代理分为静态代理和动态代理两种。
可以通过两种方式来实现静态代理,一种是继承的方式,另一种是聚合的方式。
代码演示:
假设汽车有run(行驶)和stop(停止)两个功能,通过一个CarInterface接口来表示
package cn.jie.util;
public interface CarInterface {
//卡车有行驶功能
public void run();
//卡车有停止功能
public void stop();
}
产生一辆汽车,实现该接口表示具备了行驶和停车两项功能
package cn.jie.util;
//实现接口,代表具备了两项功能
public class Car implements CarInterface{
//车辆行驶功能,实现行驶的逻辑
public void run()
{
System.out.println("车开动了!");
}
//车辆停车功能,实现停车的逻辑
public void stop()
{
System.out.println("车停下了!");
}
}
但是,我们通常行驶汽车时,需要先让汽车动起来,车才能行驶;而要让车停下来,也需要先减速。
也就是说我们在调用run方法前需要先执行给车加速的逻辑,同样,在调用stop方法前需要执行给车减速的逻辑,这样才能实现汽车驾驶的完整动作。这种情况下就可以运用到静态代理的技术。静态代理又可以通过继承和聚合两种方式来实现。
继承方式:
先产生一个汽车的代理类CarProxy,让它去继承父类Car,这样这个代理类就拥有与父类一样的run方法和stop方法,此时就可以通过覆写父类方法的方式来插入我们要执行的逻辑。
package cn.jie.util;
public class CarProxy extends Car{
public void run()
{
//给汽车加速的逻辑
System.out.println("车加速!");
super.run();
}
public void stop()
{
//给汽车减速的逻辑
System.out.println("车减速!");
super.stop();
}
}
测试汽车驾驶
由于CarProxy继承自Car类,所以我们可以通过Car类向上转型得到代理类对象,从而调用方法
package cn.jie.util;
import org.junit.Test;
public class TestCar {
@Test
public void testDrive()
{
//通过继承方式
Car car=new CarProxy();
car.run();
car.stop();
}
}
测试结果
先产生一个汽车的代理类CarProxy2,让它也去实现CarInterface接口,再将Car类以成员变量的方式引入,通过构造器赋值,此时就可以在实现的接口方法中调用Car方法和插入我们要执行的逻辑。
package cn.jie.util;
public class CarProxy2 implements CarInterface{
private Car car;
public CarProxy2(Car car) {
this.car=car;
}
@Override
public void run() {
//给汽车加速的逻辑
System.out.println("车加速!");
car.run();
}
@Override
public void stop() {
//给汽车减速的逻辑
System.out.println("车减速!");
car.stop();
}
}
测试汽车驾驶
由于都是实现CarInterface接口,所以可以通过CarInterface接口对象来调用方法。
package cn.jie.util;
import org.junit.Test;
public class TestCar {
@Test
public void testDrive()
{
//通过聚合方式
Car car=new Car();
CarInterface proxy=new CarProxy2(car);
proxy.run();
proxy.stop();
}
}
package cn.jie.util;
import org.junit.Test;
public class TestCar {
@Test
public void testDrive()
{
Car car=new LabaProxy1();
car.run();
}
}
测试结果
继承方式与聚合方式对比:
以上的Car类称为被代理类
以上的Carproxy类和Carproxy2类都是添加了汽车速度操作的逻辑,所以可以称为汽车的速度代理类
继承方式:
如果有一个需求是在汽车加速前,按一下喇叭,也就是说需要在执行加速逻辑前再先执行一个按喇叭的逻辑,那么就需要再创建一个喇叭代理类1,去继承速度代理类,然后在调用父类run方法前添加按喇叭逻辑。
实现的逻辑顺序是:按喇叭——>加速——>行驶
package cn.jie.util;
public class LabaProxy1 extends CarProxy{
public void run()
{
//按喇叭的逻辑
System.out.println("按喇叭!");
super.run();
}
public void stop()
{
super.stop();
}
}
package cn.jie.util;
import org.junit.Test;
public class TestCar {
@Test
public void testDrive()
{
Car car=new LabaProxy1();
car.run();
}
}
而如果又有一个需求是在行驶途中按喇叭,那么又需要创建一个喇叭代理类2,去继承速度代理类,然后在调用父类run方法后添加按喇叭逻辑。
实现的逻辑顺序是:加速——>行驶——>按喇叭
package cn.jie.util;
public class LabaProxy2 extends CarProxy{
public void run()
{
//按喇叭的逻辑
super.run();
System.out.println("按喇叭!");
}
public void stop()
{
super.stop();
}
}
package cn.jie.util;
import org.junit.Test;
public class TestCar {
@Test
public void testDrive()
{
Car car=new LabaProxy2();
car.run();
}
}
可以看出,实现的都是三个逻辑,只是顺序发生改变,而一旦顺序改变,就需要多创建一个代理类根据顺序来调用父类的方法。当业务有很多逻辑以及顺序很复杂的时候,需要的代理类就会有很多。
聚合方式:
由于通过聚合方式实现的静态代理的代理类都是实现同一个接口, 所以可以改为用该接口即被代理类的接口来作为参数。
速度代理类的修改
package cn.jie.util;
public class CarProxy2 implements CarInterface{
/**
* 由于通过聚合方式实现的静态代理都是实现同一个接口,
* 所以可以改为用该接口即被代理类的接口来作为参数。
*/
private CarInterface car;
public CarProxy2(CarInterface car) {
this.car=car;
}
@Override
public void run() {
//给汽车加速的逻辑
System.out.println("车加速!");
car.run();
}
@Override
public void stop() {
//给汽车减速的逻辑
System.out.println("车减速!");
car.stop();
}
}
实现的逻辑顺序是:按喇叭——>加速——>行驶
由于新增了喇叭逻辑,所以要创建一个喇叭代理类LabaProxy3package cn.jie.util;
public class LabaProxy3 implements CarInterface{
private CarInterface car;
public LabaProxy3(CarInterface car) {
this.car=car;
}
@Override
public void run() {
//按喇叭的逻辑
System.out.println("按喇叭!");
car.run();
}
@Override
public void stop() {
car.stop();
}
}
package cn.jie.util;
import org.junit.Test;
public class TestCar {
@Test
public void testDrive()
{
//被代理类
Car car=new Car();
//速度代理类
CarProxy2 cp=new CarProxy2(car);
//喇叭代理类
CarInterface proxy=new LabaProxy3(cp);
proxy.run();
}
}
测试结果
实现的逻辑顺序是:加速——>按喇叭——>行驶
只需要在测试类中更换调用顺序即可
package cn.jie.util;
import org.junit.Test;
public class TestCar {
@Test
public void testDrive()
{
//被代理类
Car car=new Car();
//喇叭代理类
CarInterface proxy=new LabaProxy3(car);
//速度代理类
CarProxy2 cp=new CarProxy2(proxy);
cp.run();
}
}
测试结果
总结:
继承方式:每多一个逻辑,多一个代理类;逻辑顺序改变一次顺序,多一个代理类
聚合方式:每多一个逻辑,多一个代理类;逻辑顺序改变一次顺序,只需在调用时改变顺序
而且可以看到,无论是继承方式还是聚合方式,得到的代理类对象与被代理类对象不是同一个对象。