我发现自己面临着很多类似的方法,在我的项目中有一些重复的代码。一般模式似乎是这样的(对模糊的代码表示歉意,许可不会让我提供一个具体的例子(:
public void modifyType1Person() {
Map<String, ?> parameters = new HashMap<>();
parameters.put("type", "type1");
parameters.put("stringArgument", "some name");
editPersonBasedOnType(parameters);
}
public void modifyType2Person() {
Map<String, ?> parameters = new HashMap<>();
parameters.put("type", "type2");
editPersonBasedOnType(parameters);
}
public void modifyDefaultTypePerson() {
Map<String, ?> parameters = new HashMap<>();
parameters.put("type", "otherType");
parameters.put("booleanArgument", true);
editPersonBasedOnType(parameters);
}
public void editPersonBasedOnType(Map<String, ?> parameters) {
// assume some stuff is done
switch (parameters.get("type")) {
case "type1":
editType1Person(parameters.get("stringArgument"));
case "type2":
editType2Person();
default:
editOtherType(parameters.get("type"), parameters.get("booleanArgument"));
}
// assume more stuff is done
}
private void editType1Person(String stringArg) {
Person person = PersonService.getPerson(stringArg);
person.edit();
doMoreThingsForType1Person(person);
}
private void editType2Person() {
Person person = PersonService.getPerson(HARDCODED_NAME);
person.edit();
doMoreThingsForType2Person(person);
}
private void editOtherType( String type, boolean boolArg ) {
Person person = PersonService.getPerson(HARDCODED_NAME);
person.edit()
doMoreThingsForDefaultTypePerson(person)
}
"doMoreThingsForTypeXPerson"方法可以相似或不相似,具体取决于上下文。
就我个人而言,我觉得可以使用策略模式或依赖注入来摆脱类似的代码,并消除为每个类型编写多个方法的需要,因此它看起来像:
public void modifyType1Person() {
editPersonBasedOnType(new Type1Strategy("some name"));
}
public void modifyType2Person() {
editPersonBasedOnType(new Type2Strategy());
}
public void modifyDefaultTypePerson() {
editPersonBasedOnType(new DefaultTypeStrategy("other type", true));
}
public void editPersonBasedOnType(TypeStrategy typeStrategy) {
// assume some stuff is done
typeStrategy.doProcedure();
// assume more stuff is done
}
public interface TypeStrategy {
public void doProcedure()
}
public class Type1Strategy {
private String stringArgument;
public Type1Strategy(String stringArgument) {
this.stringArgument = stringArgument;
}
public void doProcedure() {
// editType1Person method
}
private void doMoreThingsForType1Person() {//implementation}
}
public class Type2Strategy {
public void doProcedure() {
// editType2Person method
}
private void doMoreThingsForType2Person() {//implementation}
}
public class DefaultTypeStrategy {
private String type;
private boolean boolArg;
public DefaultTypeStrategy(String type, boolean boolArg) {
this.type = type;
this.boolArg = boolArg;
}
public void doProcedure() {
// editOtherType code
}
private void doMoreThingsForDefaultTypePerson() {//implementation}
}
您会使用第一种方法还是重构方法?或者对于这种一般情况,有更好的方法吗?是否需要关注实例化策略对象的成本?
每当您将具体类型的分支代码(一堆 if/else 语句或开关(交换为抽象和多态的东西时,您通常会支付更高的成本,只有最罕见的例外(例如:当 icache 命中变得重要时(,如果您涉及一些查找作为交换,例如Map
,可能会更高。
这样做通常考虑到可扩展性,以便您可以扩展原始代码支持的内容,而无需不断修改它(例如:避免不断摆弄editPersonBasedOnType
(或对其进行过多修改。有时,如果无法继续编辑此类函数直到时间结束,例如如果行为应该通过第三方添加扩展行为范围的插件来扩展,则成为一种必要。
因此,您是喜欢这里的可扩展性还是性能取决于您,但值得注意的是,这里通常有一些微效率排序的性能开销。还值得注意的是,生产力通常胜过微观级别的性能,除了在探查器中显示的代码库中最紧凑、最循环的部分。
所以我会选择任何适合您需求的设计。在您的示例代码中,我假设它已比原始代码简化,并且我不赞成只在一个地方对 3 种类型的可能性进行切换的路线。更智能的解决方案只有在真正减轻负担时才是智能的。但也许你的原始代码要广泛得多,并且成为维护负担,并有广泛的计划继续扩展和扩展它,如果是这样,可能值得重构为多态设计。