设计模式在Java中非常重要,在此把Animal接口和Dog类(实现Animal接口)作为基准,分别写出用装饰者模式、静态代理模式和动态代理模式改造say方法的代码,为了和这三种模式写出的代码比较,先写一个熟悉的继承Dog类的代码,所有代码和运行结果如下所示:
1、Animal接口:
package com.huanletao.test;
public interface Animal {
//定义吃方法
public void eat();
//定义说方法
public void say();
}
2、Dog类
package com.huanletao.test;
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("狗在么么么地吃");
}
@Override
public void say() {
System.out.println("狗在汪汪汪地叫");
}
//再重新写一个睡觉的方法
public void sleep(){
System.out.println("狗在睡觉......");
}
}
3、继承
package com.huanletao.test;
public class Dog_extends extends Dog {
@Override
public void say() {
System.out.println("狗在喵喵喵地叫");
}
}
4、装饰者模式
package com.huanletao.test;
public class Dog_ZS implements Animal {
// 装饰者首先实现和被装饰者同一个接口,然后弄一个有参构造,把对象放进去
// 接口不是创建对象没有意义吗?这里只是声明从而统一类型,并没有创建?private这一行只是故意设定一个对象,体现装饰者作用。
// 不,是为了this.ani=ani用的。
private Animal ani = null;
public Dog_ZS(Animal ani) {
this.ani = ani;
}
@Override
public void eat() {
ani.eat();
}
@Override
public void say() {
System.out.println("狗在没没没的叫");
}
}
5、静态代理模式
package com.huanletao.test;
public class Dog_StaticProxy implements Animal{
private Dog dog = new Dog();
@Override
public void eat() {
//代理了被代理者dog的eat方法
dog.eat();
}
@Override
public void say() {
//没有代理被代理者dog的say方法,自己重写了
System.out.println("狗在哈哈哈地叫");
}
}
继承、装饰和静态代理的测试类代码如下所示:
package com.huanletao.test;
import org.junit.Test;
//Test不能作为类名,因为是关键字
public class DogTest{
//1、测试继承——向上造型,有什么方法看父类,具体什么方法看子类
@Test
public void test01(){
Dog dog = new Dog_extends();
dog.eat();
dog.say();
}
//2、测试装饰——首先创建被装饰类的对象,然后把这个对象放到装饰类的有参构造里
@Test
public void test02(){
Dog dog = new Dog();
Dog_ZS zsdog = new Dog_ZS(dog);
zsdog.eat();
zsdog.say();
}
//3、测试静态代理——直接用静态代理类创建对象即可
@Test
public void test03(){
Dog_StaticProxy sproxydog = new Dog_StaticProxy();
sproxydog.eat();
sproxydog.say();
}
}
运行结果:
狗在么么么地吃
狗在喵喵喵地叫
狗在么么么地吃
狗在没没没的叫
狗在么么么地吃
狗在哈哈哈地叫
6、动态代理模式(java自带的Proxy类)
package com.huanletao.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Dog_Proxy {
public static void main(String[] args) {
//创建被代理类的对象
//注意动态代理中被代理者只能设置为final类!此时不能有private,因为二者不能共存!
final Dog dog = new Dog();
//调用java自带的Proxy静态类的newProxyInstance()方法生成代理者,这个代理者的类型是接口,即Animal
Animal proxy = (Animal) Proxy.newProxyInstance(
//第一个参数是生成代理者的加载器,和代理者的一样即可
dog.getClass().getClassLoader(),
//第二个参数是生成代理者实现的接口们, 和代理者的一样,从而保证方法一样
dog.getClass().getInterfaces(),
//第三个参数最重要,创建一个类实现InvocationHandler接口(直接new不需要implement),并实现其中的invoke方法
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//如果调用代理者的方法名是say则输出下面内容,否则输出另一种内容。
if("say".equals(method.getName())){
System.out.println("狗在666地叫");
return null;
}else{
//这里的第一个参数obj是被代理者dog
return method.invoke(dog, args);
}
}
});
//从此只能调用动态代理者身上的方法,不能调用被代理者身上的方法
proxy.eat();
proxy.say();
}
}
动态代理模式没有写测试类,直接main函数运行结果如下:
狗在么么么地吃
狗在666地叫
注:如果觉得在静态类Proxy的newProxyInstance()方法里第三个参数这样写比较难以理解,可以在外面创建一个类实现InvocationHandler接口,并实现里面的invoke方法,然后这里就可以不写main方法,而是写在上面的测试类中,然后在测试方法中调用静态类Proxy的newProxyInstance()方法,方法中第三个参数直接new写好的InvocationHandler接口的实现类即可。