将类似方法重构为策略模式的性能成本



我发现自己面临着很多类似的方法,在我的项目中有一些重复的代码。一般模式似乎是这样的(对模糊的代码表示歉意,许可不会让我提供一个具体的例子(:

 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 种类型的可能性进行切换的路线。更智能的解决方案只有在真正减轻负担时才是智能的。但也许你的原始代码要广泛得多,并且成为维护负担,并有广泛的计划继续扩展和扩展它,如果是这样,可能值得重构为多态设计。

最新更新