读书人

【设计】一个好玩儿的服务方法入参设计

发布时间: 2012-10-14 14:55:08 作者: rapoo

【设计】一个有意思的服务方法入参设计

今天晚上和项目组的几个同学讨论一个服务方法的入参设计,觉得挺有意思的,在此记录一下!

?

背景

我们的场景需要对外暴露一个远程服务写入接口,用于给几个外部同步数据的场景。

由于历史的原因,需要被写入的这个业务对象很大,字段很多(100多个字段,也会涉及多个表)。

以下是场景提取出来的一些要求:

1.这个场景只需要同步更新几个字段到该主表里。为了数据安全和方便理解,不希望把整个业务对象暴露出来,希望只暴露几个该场景可以写入的字段。

2.外部场景都是能拿到该业务对象的唯一外键的,所以为了交互友好,不希望流程是"远程读取数据-->修改数据-->远程更新数据",而希望是"拼装需要同步的数据-->远程同步"的流程。

?

注:用的是公司内部应用的的java远程调用服务框架,只在java语言内部调用。只考虑java 语言层面的设计,不考虑soap这些重量级的方案。

入参的设计方案方案一

一开始想得是设计一个只包含可更新字段的pojo model类作为入参。如:

public class WritableModel {String property1;String peoperty2;public String getProperty1() {return property1;}public void setProperty1(String property1) {this.property1 = property1;}public String getPeoperty2() {return peoperty2;}public void setPeoperty2(String peoperty2) {this.peoperty2 = peoperty2;}}

?这个model强类型固然好,但是有一个很难避免的问题就是二义性。

在property1为null的时候,是说明不更新这个字段还是要清空这个字段呢?(注意:在这里的写场景里这两种情况都需要支持!)

强类型虽然约束了可更新范围,这个时候pojo里的null是没办法去理解。

?

方案二

由于方案一的缺陷根本就没办法满足需求,于是想了下用map来作为入参,但是map是弱类型,我们必须定义一些key,并让调用方只用这个key。于是想到了将key用一个枚举来表示,然后入参用java map泛型来约束.

如下:

key的枚举类设计如下:

public enum WritablePropertyType {PROPERTY1_NAME//属性1的名字, PROPERTY2_NAME//属性2的名字}

?服务方法入参设计如下:

/** *  * @param map  需要被同步的字段 * @return 是否成功 */public boolean sync(Map<WritablePropertyType,Object> map);

以上虽然很简洁,对于调用者只需要将自己需要更新的字段拼装成map,同时key使用WritablePropertyType 泛型约束。如果需要对某个字段清空,只需要put一个null值进来就行了。

但是泛型约束并不那么强,对于不遵循泛型的map的入参虽会有警告但是没办法做到强类型的约束,还是存在一些风险。难道在服务端进行key类型检查,不规范的抛异常吗?为了更好的约束,又有了方案三。

?

方案三

方案二随能很好满足需求,但是泛型毕竟约束是不够的,于是想了方案三。基本是延续方案二的思路,用map。也是由自己设计的WritablePropertyType 枚举作为map的key。但是要对map做一些改造,使得map只能放进来以WritablePropertyType作为key的map。于是想到对HashMap做一个扩展,只是简单的复写put方法,并在put方法里强制检查。

复写的map如下:

import java.util.HashMap;public class WritableMap<K, V> extends HashMap<K, V> {/** *  */private static final long serialVersionUID = 1L;public V put(K key, V value) {if (key instanceof WritablePropertyType) {//强制检查super.put(key, value);return value;} else {throw new IllegalArgumentException("key type must be WritablePropertyType");}}}
?

?服务方法入参设计如下:

/** *  * @param map  需要被同步的字段 * @return 是否成功 */public boolean sync(WritableMap<WritablePropertyType,Object> map);

?

?

?

?

以上方案三是最后定下来一个折中的方案,相信这还不是最优方案,不知道大家有没有更好的方案?说说你的观点吧,:)

读书人网 >编程

热点推荐