直接转帖ajoo的大作
http://www.iteye.com/topic/190440
内容节选如下:
- Map <String, String>
Map
<String, String>
非常非常复杂深奥。
好,现在我们事先知道要从这个map 里读取一些数据点,比如:id , name , sex等等。
对id ,我们知道读出来的是int;对name ,是string;对sex,应该对应一个叫Gender的enum类型。
这就涉及一个自动类型转换的问题。我们希望不用对每个数据点做手工类型转换。
另外一个需求,一些数据点是有缺省值的。比如name 我们可以缺省为空字符串。
这样,如果map 里面没有某个值,我们就看缺省值,如果有,就用这个缺省值,如果没有,就抛异常。
手工做的话,大概是这样:
- String id Value = map .get( "id " );
- if (id Value == null ) {
- throw ...;
- }
- int id = Integer.parseInt(id Value);
- String name = map .get( "name " );
- if (name == null ) {
- name = "" ;
- }
- String sexValue = map .get( "sex" );
- if (sexValue == null ) {
- throw ...;
- }
- Gender sex = Gender.valueOf(sexValue);
- ...
String id
Value = map
.get("id
"); if (id
Value == null) { throw ...; } int id
= Integer.parseInt(id
Value); String name
= map
.get("name
"); if (name
== null) { name
= ""; } String sexValue = map
.get("sex"); if (sexValue == null) { throw ...; } Gender sex = Gender.valueOf(sexValue); ...
比较痛苦。于是做了一个动态代理 :
- public final class PropertyConverter<T> {
- private final Class<T> targetType;
- private PropertyConverter(Class<T> targetType) {...}
- public static <T> PropertyConverter<T> to(Class<T> targetType) {
- return new PropertyConverter<T>(targetType);
- }
- public T from( final Map <String, String> map ) {
- return Proxy.newProxyInstance(
- new Class[]{targetType}, targetType.getClassLoader(), new InvocationHandler() {
- public Object invoke(Object proxy, Method method, Object[] args) {
- String value = map .get(method.getName ());
- if (value == null ) {
- Object defaultValue = method.getDefaultValue();
- if (defaultValue == null ) {
- throw ...;
- }
- return defaultValue;
- }
- return convert(value, method.getReturnType());
- }
- });
- }
- }
public final class PropertyConverter<T> { private final Class<T> targetType; private PropertyConverter(Class<T> targetType) {...} public static <T> PropertyConverter<T> to(Class<T> targetType) { return new PropertyConverter<T>(targetType); } public T from(final Map
<String, String> map
) { return Proxy.newProxyInstance( new Class[]{targetType}, targetType.getClassLoader(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) { String value = map
.get(method.getName
()); if (value == null) { Object defaultValue = method.getDefaultValue(); if (defaultValue == null) { throw ...; } return defaultValue; } return convert(value, method.getReturnType()); } }); } }
convert()函数是调用apache的ConvertUtilsBean做的,没什么说的。
那么,用法呢?
- @interface Foo {
- int id ();
- String name () default "" ;
- Gender sex();
- }
- Map <String, String> map = ...;
- Foo foo = PropertyConverter.to(Foo. class ).from(map );
- foo.id ();
- foo.name ();
@interface Foo { int id
(); String name
() default ""; Gender sex(); } Map
<String, String> map
= ...; Foo foo = PropertyConverter.to(Foo.class).from(map
); foo.id
(); foo.name
();
这里面,对annotation的用法比较特别。不过不这么做,java也不提供一个简单并且类型安全的指定缺省值的方法。当然,如果你凑巧不需要缺省值,那么也不用annotation,直接用interface就好。
我的补充:
动态代理(或者静态代理模式)在处理通用过程方面确实是非常常见的解决方案。
我们目前用到的spring的事务管理模块,buffalo,都是采用的动态代理技术。
做了这么久的开发,作为一个中级程序员,看到很繁琐累赘的代码四散在项目里时,我们就应该考虑设计模式了。
因为良好的设计,往往可以减少大量的代码量和工作时间,使项目结构清晰易读,容易重构升级,并减少bug!
不同于软件界面的改进,虽然老板看不见(/看不懂)产品内在的进化和我们冥思苦想的技术结晶,但它可以让我们活得更轻松,做得更好,更加游刃有余。
我一直自认是个”懒“人,也觉得每个程序员都应该变得更”懒“,凡是可以让我们更快开发,更快测试,更快发布的技术/方案/思想都应该迅速学习和接收,自己也要能开发、积累趁手的工具来加强效率。
据说IBM有个统计,不同水平程序员之间的开发效率差距最大可以达到恐怖的20倍!估计那都是日积月累之功,但如果个体不会思考,不想进步,那工作再久也是不能升华的。
谨以此同勉!
【2008-6 bbs】
后记:
后来我在项目应用了这个技巧,读取配置文件很方便,主要是有代码完成。缺点是如果增添配置文件的属性则需要增添接口的方法,这带来一点麻烦。