我有以下方法:
[DataContract]
public class InvestigatorGroupData
{
[DataMember]
public int InvestigatorGroupId { get; set; }
[DataMember]
public string InvestigatorGroupName { get; set; }
}
如果语句以类似的方式使用,则会再增加12个。唯一的区别是不同的setter方法名称和不同的参数。
现在,由于一次又一次地重复相同的模式,有没有办法降低代码复杂度?
答案 0 :(得分:2)
不容易,也不是没有使用反射。
使用反射,您可以遍历值列表并在客户端对象中调用适当的方法。这将摆脱复杂性,更清洁/更强大。然而,它也会表现得更慢。
从根本上说,虽然你遇到的情况是你一直在做几乎但不完全相同的操作,但这总是很棘手。
答案 1 :(得分:1)
您可以使用Java 8功能接口执行此操作。它至少可以摆脱重复的条件陈述。
private void doRepetitiveThing(Map info, String key, Consumer<String> setterFunction) {
if(checkMapProperty(info, key)) {
setterFunction.accept(info.get(key).toString());
}
}
private void setClientAdditionalInfo(Map map, Client client, User user) {
Map additionalInfo = (Map) map.get("additionalInfo");
doRepetitiveThing(additionalInfo, "gender", client::setGender);
doRepetitiveThing(additionalInfo, "race", client::setRace);
doRepetitiveThing(additionalInfo, "ethnicity", client::setEthnicity);
.....
答案 2 :(得分:1)
不确定这是否真的降低了圈复杂度,但它使代码更漂亮。使用Java 8更容易。
private void setClientAdditionalInfo(Map<String, Object> map, Client client, User user) {
Map<String, ?> additionalInfo = (Map<String, Object>) map.get("additionalInfo");
setIfPresent(additionalInfo, "gender", client::setGender);
setIfPresent(additionalInfo, "race", client::setRace);
setIfPresent(additionalInfo, "ethnicity", client::setEthnicity);
}
private void <T> setIfPresent(Map<String, ?> additionalInfo,
String property,
Consumer<T> consumer) {
if (checkMapProperty(additionalInfo, property)) {
consumer.apply((T)additionalInfo.get(property));
}
}
如果您愿意,可以制作Map<String, Consumer<?>>
以避免重复通话。
答案 3 :(得分:0)
我使用enum
使用name().toLowercase()
作为密钥,将设置器与地图键连接起来。
enum Setter {
Gender {
@Override
void set(Client client, Thing value) {
client.setGender(value);
}
},
Race {
@Override
void set(Client client, Thing value) {
client.setRace(value);
}
},
Ethnicity {
@Override
void set(Client client, Thing value) {
client.setEthnicity(value);
}
};
void setIfPresent(Client client, Map<String, Thing> additionalInfo) {
// Use the enum name in lowercase as the key.
String key = this.name().toLowerCase();
// Should this one be set?
if (additionalInfo.containsKey(key)) {
// Yes! Call the setter-specific set method.
set(client, additionalInfo.get(key));
}
}
// All enums must implement one of these.
abstract void set(Client client, Thing value);
}
private void setClientAdditionalInfo(Map map, Client client, User user) {
Map additionalInfo = (Map) map.get("additionalInfo");
for (Setter setter : Setter.values()) {
setter.setIfPresent(client, additionalInfo);
}
}
答案 4 :(得分:0)
如果地图不包含属性,假设Client
的字段可以设置为null
,则可以创建一个类:
class MapWrapper {
private final Map map;
MapWrapper(Map map) {
this.map = map;
}
String get(String key) {
if (checkMapProperty(map,key)) {
return map.get(key).toString();
} else {
return null;
}
// or more concisely:
// return checkMapProperty(map,key) ? map.get(key).toString() : null;
}
}
然后
private void setClientAdditionalInfo(Map map, Client client, User user) {
Map additionalInfo = (Map) map.get("additionalInfo");
MapWrapper wrapper = new MapWrapper(additionalInfo);
client.setGender(wrapper.get("gender"));
...
}
但是,如果要求在地图中没有相应的关键字时保留Client
字段,则无法帮助您。
答案 5 :(得分:0)
仅作为回答OP问题的练习,我创建了Map
将属性与setter界面相关联:
private static Map<String, ClientSetter> setters = new HashMap<>();
interface ClientSetter {
void set(Client client, Object value);
}
static {
setters.put("gender", new ClientSetter() {
@Override
public void set(Client client, Object value) {
client.setGender(value.toString());
}
});
setters.put("race", new ClientSetter() {
@Override
public void set(Client client, Object value) {
client.setRace(value.toString());
}
});
setters.put("ethnicity", new ClientSetter() {
@Override
public void set(Client client, Object value) {
client.setEthnicity(value.toString());
}
});
// ... more setters
}
迭代可用的属性,并为set
地图中的每个可用属性调用setters
方法:
private void setClientAdditionalInfo(Map map, Client client, User user) {
Map additionalInfo = (Map) map.get("additionalInfo");
List<String> additionalInfoKeys = new ArrayList<>(additionalInfo.keySet());
additionalInfoKeys.retainAll(setters.keySet());
for (String key: additionalInfoKeys) {
Object value = additionalInfo.get(key);
setters.get(key).set(client, value);
}
}
PS:显然这不是生产代码的建议。将集合的所有元素复制到用于交叉两组的列表 - 为了防止被测试/编写的代码中的条件 - 是非常昂贵的。