对象增强常用的三种方式:
- 继承
- 装饰
- 代理
最简单的方式就是继承父类,子类扩展来达到目的。虽然简单,但是这种方式的缺陷非常大:
装饰模式:
- 一、如果父类是带有数据、信息、属性的话,那么子类无法增强。
- 二、子类实现了之后需求无法变更,增强的内容是固定的。
场景:二次开发的时候,无法获取到源码,无法使用继承前提下,要对已经存在对象上的功能进行增强.
前提: 可以获取到被装饰的对象GoogleCar实现的所有接口
实现思路: 自定定义装饰类实现ICar接口,为自定义装饰类传递被装饰的对象
弊端:如果被实现的接口中的方法过多,装饰类中的方法过多冗余
Google汽车案例:
【/SingleInstance/it.cast.single.demo】
Icar接口汽车制造标准 : Icar
public interface Icar {
void start();
void run();
void stop();
}
谷歌汽车,实现了Icar接口:GoogleCar
public class GoogleCar implements Icar {
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("Google start...");
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Google run...");
}
@Override
public void stop() {
// TODO Auto-generated method stub
System.out.println("Google stop...");
}
}
GoogleCar的装饰类,同样实现了Icar接口,定义了以接口为参数的构造函数,增强了GoogleCar的方法:MycarWraper
public class MycarWraper implements Icar {
private Icar car;
public MycarWraper(Icar car) {
super();
this.car = car;
}
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("检查天气是否良好。。。");
car.start();
System.out.println("检查路况是否良好。。。");
}
@Override
public void run() {
// TODO Auto-generated method stub
car.run();
}
@Override
public void stop() {
// TODO Auto-generated method stub
car.stop();
}
}
测试装饰着模式:TestDemo
public class TestDemo {
@Test
public void testCar() {
//把GoogleCar传进去
Icar icar=new MycarWraper(new GoogleCar());
icar.start();
icar.run();
icar.stop();
}
}
动态代理:通过创建指定的字节码文件来解决装饰着模式的弊端
Icar接口汽车制造标准 ,给start方法增加了参数和返回值: Icar
public interface Icar {
String start(int a,int b);
void run();
void stop();
}
谷歌汽车,实现了Icar接口:
public class GoogleCar implements Icar {
@Override
public String start(int a,int b) {
System.out.println("Google start...");
return a+b+"Google";
}
@Override
public void run() {
System.out.println("Google run...");
}
@Override
public void stop() {
System.out.println("Google stop...");
}
}
测试getInterfaces方法:获取一个类上的接口:TestMethod
public class TestMethod {
public static void main(String[] args) {
// TODO Auto-generated method stub
//获取GoogleCar类上的接口
Class[] interfaces = GoogleCar.class.getInterfaces();
//因为GoogleCar上只有一个接口,所以取数组的第一个值获得icar接口
Class icar=interfaces[0];
//获取Icr接口里面的方法
Method[] methods = icar.getMethods();
for (Method method : methods) {
//打印方法名
System.out.println(method.getName());
}
}
}
测试动态代理:TestCar
public abstract class TestCar {
public static void main(String[] args) {
//1param: 固定值: 告诉虚拟机用哪个字节码加载器加载内存中创建出的字节码文件,一般用本类的加载器
//2param: 告诉虚拟机内存中正在被创建的字节码文件中应该有哪些方法
//3param: 告诉虚拟机正在被创建的字节码上的各个方法如何处理
Icar car=(Icar)Proxy.newProxyInstance(TestCar.class.getClassLoader(), GoogleCar.class.getInterfaces(),new InvocationHandler() {
//method:代表正在执行的方法
//args:代表正在执行的方法中的参数
//Object:代表方法执行完毕之后的返回值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行当前的方法
//method.invoke(new GoogleCar(), args);
//运行方法返回的结果
Object rs=null;
if (method.getName().equalsIgnoreCase("start")) {
System.out.println("检查天气是否良好。。。");
//打印start方法的参数
System.out.println(Arrays.toString(args));
rs=method.invoke(new GoogleCar(), args);
System.out.println("检查路况是否良好。。。");
} else {
rs=method.invoke(new GoogleCar(), args);
}
return rs;
}
}
}