首页 » 编写高质量代码:改善Java程序的151个建议 » 编写高质量代码:改善Java程序的151个建议全文在线阅读

《编写高质量代码:改善Java程序的151个建议》建议107:使用反射增加装饰模式的普适性

关灯直达底部

装饰模式(Decorator Pattern)的定义是“动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比于生成子类更为灵活”,不过,使用Java的动态代理也可以实现装饰模式的效果,而且其灵活性、适应性都会更强。

我们以卡通片《猫和老鼠》(《Tom and Jerry》)为例,看看如何包装小Jerry让它更强大。首先定义Jerry的类:老鼠(Rat类),代码如下;


interface Animal{

public void doStuff();

}

//老鼠是一种动物

class Rat implements Animal{

public void doStuff(){

System.out.println("Jerry will play with Tom.");

}

}


接下来我们要给Jerry增加一些能力,比如飞行、钻地等能力,当然使用类继承也很容易实现,但我们这里只是临时地为Rat类增加这些能力,使用装饰模式更符合此处的场景。首先定义装饰类,代码如下:


//定义某种能力

interface Feature{

//加载特性

public void load();

}

//飞行能力

class FlyFeature implements Feature{

public void load(){

System.out.println("增加一只翅膀……");

}

}

//钻地能力

class DigFeature implements Feature{

public void load(){

System.out.println("增加钻地能力……");

}

}


此处定义了两种能力:一种是飞行,另一种是钻地,我们如果把这两种属性赋予到Jerry身上,那就需要一个包装动作类了,代码如下:


class DecorateAnimal implements Animal{

//被包装的动物

private Animal animal;

//使用哪一个包装器

private Class<?extends Feature>clz;

public DecorateAnimal(Animal_animal, Class<?extends Feature>_clz){

animal=_animal;

clz=_clz;

}

@Override

public void doStuff(){

InvocationHandler handler=new InvocationHandler(){

//具体包装行为

public Object invoke(Object p, Method m, Objectargs)throws

Throwable{

Object obj=null;

//设置包装条件

if(Modifier.isPublic(m.getModifiers())){

obj=m.invoke(clz.newInstance(),args);

}

animal.doStuff();

return obj;

}

};

//当前加载器

ClassLoader cl=getClass().getClassLoader();

//动态代理,由Handler决定如何包装

Feature proxy=(Feature)Proxy.newProxyInstance(cl, clz.

getInterfaces(),handler);

proxy.load();

}

}


注意看doStuff方法,一个装饰类型必然是抽象构建(Component)的子类型,它必须要实现doStuff,此处的doStuff方法委托给了动态代理执行,并且在动态代理的控制器Handler中还设置了决定装饰方式和行为的条件(即代码中InvocationHandler匿名类中的if判断语句),当然,此处也可以通过读取持久化数据的方式进行判断,这样就更加灵活了。

抽象构件有了,装饰类也有了,装饰动作类也完成了,那我们就可以编写客户端进行调用了,代码如下:


public static void main(Stringargs)throws Exception{

//定义Jerry这只家喻户晓的老鼠

Animal Jerry=new Rat();

//为Jerry增加飞行能力

Jerry=new DecorateAnimal(Jerry, FlyFeature.class);

//Jerry增加挖掘能力

Jerry=new DecorateAnimal(Jerry, DigFeature.class);

//Jerry开始耍猫了

Jerry.doStuff();

}


此类代码是一个比较通用的装饰模式,只需要定义被装饰的类及装饰类即可,装饰行为由动态代理实现,实现了对装饰类和被装饰类的完全解耦,提供了系统的扩展性。