虽然面向接口编程回比直接面向具体类编程增加一点点的复杂性,但是带来的好处却是巨大的。
1)、可以改变实现而不改变调用的代码。这使我们可以重新实现程序的一部分,而不用去修改其它部分。 2)、可以自由的实现接口,并促进重用。 3)、必要的时候可以写出一个简单的测试实现,或者Stub实现。模版模式是直接类继承的一种正确使用。但你知道一些算法的步骤,但是不清楚他们的具体操作就可以使用模版模式,将具体的操作留到以后实现。依赖倒转 (IOC/Inversion of Control)就是模版模式的一种使用,它通过模版模式,让框架代码调用用户自己的代码,而不是正常的那种用户代码去掉用框架的代码。模版模式特别适用 于框架设计。
public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException {是一个正常的属性检查的代码,但是如果我们需要增加或者删除一个属性,我们就需要修改这些判断,这意味着我们需要重新测试。但是如果我们使用反射,就可以非常优雅的解决怎么问题
if (e.getPropertyName() .equals ("email")) {
String email = (String) e.getNewValue();
validateEmail (email, e);
}
...
} else if (e.getPropertyName() .equals ("age")) {
int age = ((Integer) e.getNewValue()).intValue();
validateAge(age, e);
} ...
}
public AbstractVetoableChangeListener() throws SecurityException {虽然,使用反射的代码要比正常的代码复杂了一点,但是他只需要测试一遍,就可以应对可能的修改,这样才能说是框架性的代码!反射是Java的核心API,所以必须掌握。 反射和工厂模式(Reflection and the Factory Design Pattern)
Method[] methods = getClass() .getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i] .getName() .startsWith(VALIDATE_METHOD_PREFIX) &&
methods[i] .getParameterTypes() .length == 2 &&
PropertyChangeEvent.class.isAssignableFrom(methods[i].
getParameterTypes() [1])) {
// We've found a potential validator
Class[] exceptions = methods[i] .getExceptionTypes();
// We don't care about the return type, but we must ensure that
// the method throws only one checked exception, PropertyVetoException
if (exceptions.length == 1 &&
PropertyVetoException.class.isAssignableFrom(exceptions[0])) {
// We have a valid validator method
// Ensure it's accessible (for example, it might be a method on an
// inner class)
methods[i].setAccessible(true);
String propertyName = Introspector.decapitalize(methods[i].getName().
substring(VALIDATE_METHOD_PREFIX.length()));
validationMethodHash.put(propertyName, methods[i]);
System.out.println(methods[i] + " is validator for property " +
propertyName);
}
}
}
} public final void vetoableChange(PropertyChangeEvent e)
throws PropertyVetoException {
Method m = (Method) validationMethodHash.get(e.getPropertyName());
if (m != null) {
try {
Object val = e.getNewValue();
m.invoke(this, new Object[] { val, e });
} catch (IllegalAccessException ex) {
System.out.println("WARNING: can't validate. " +
"Validation method "' + m + "' isn't accessible");
} catch (InvocationTargetException ex) {
// We don't need to catch runtime exceptions
if (ex.getTargetException() instanceof RuntimeException)
throw (RuntimeException) ex.getTargetException();
// Must be a PropertyVetoException if it's a checked exception
PropertyVetoException pex = (PropertyVetoException)
ex.getTargetException();
throw pex;
}
}
}
public Object getObject(String classname, Class requiredType)使用反射时,一般都会导致我们不能确定代码是否能够正常被执行,这是就要求我们必须提供更详细的错误信息,以方便以后的处理。 动态代理(Java 1.3 Dynamic Proxies) 第11章(Infrastructure and Application Implementation)会详细介绍,是一个和AOP(Aspect Oriented Programming )相关的东西。
throws FactoryException {
try {
Class clazz = Class.forName(classname);
Object o = clazz.newInstance();
if (! requiredType.isAssignableFrom(clazz))
throw new FactoryException("Class "' + classname +
"' not of required type " + requiredType);
// Configure the object...
return o;
} catch (ClassNotFoundException ex) {
throw new FactoryException("Couldn't load class "' + classname + ""', ex);
} catch (IllegalAccessException ex) {
throw new FactoryException("Couldn't construct class "' + classname + "': is the no arg constructor public?", ex);
} catch (InstantiationException ex) {
throw new FactoryException("Couldn't construct class "' + classname +
"': does it have a no arg constructor", ex);
}
}
使用: MyInterface mo = (MyInterface)
beanFactory.getObject("com.mycompany.mypackage.MyImplementation",
MyInterface.class);
PropertyEditor
PropertyChangeListener
VetoableChangeListener
Introspector