工厂模式创建预构建的构建器

时间:2015-12-01 18:30:58

标签: design-patterns

我有一个SearchRequest对象,可以使用SearchRequestBuilder创建。我们的一些预定义SearchRequestBuilder可能非常复杂。我已经看到工厂模式用于创建相同父对象的不同类型,但我想知道这是否适当的设计有这样的东西:

public class SearchRequestBuilderFactory {

    public enum Type {
        SEARCH, MATCH
    }

    public SearchRequestBuilder createBuilder(Type type) {
        switch (type) {
        case SEARCH:
            return createSearchBuilder();
            break;
        case MATCHING:
            return createMatchBuilder();
            break;
        }
    }

    private SearchRequestBuilder createSearchBuilder() {
        SearchRequestBuilder srb = new SearchRequestBuilder();
        srb.addField("*");
        srb.addFilter("searchFilter");
        return srb;
    }

    private SearchRequestBuilder createMatchBuilder() {
        SearchRequestBuilder srb = new SearchRequestBuilder();
        srb.addFilter("matchFilter");
        srb.addThreshold(0.5);
        return srb;
    }
}

2 个答案:

答案 0 :(得分:2)

没有建设工厂的限制。但是他们出于某种原因并不常见......

只要对象的属性对其构造不是强制性的,我们就使用Builder。我不知道你的申请是否属实。因此,我将尝试给出一个涵盖所有场景的正确答案。

情景1:某些班级成员仅在特定模式下使用。在这种情况下,实际的课程需要分为不同的课程。在您的情况下,如果属性阈值永远不会成为搜索请求的一部分,那么它不应该是SearchRequest类的一部分,并且您应该有一个MatchRequest类来保存它。

情景2:所有属性都在使用中,但在某种模式下,其中一些属性将具有常量值,我们永远不会在外部更改。在这种情况下,我们使用不同的构建器(具有继承)而不是工厂。这将限制外部这些属性的可访问性,这是必需的。

情景3:所有属性都在使用中,但在某种模式下,其中一些属性具有预定义值,可能会在外部发生变化。在这里,我建议使用与2相同的解决方案,因为它比使用工厂更具可读性,可维护性和SRP。因此,例如在您的情况下,假设传递给addField()的值需要更改为“”,并且传递给addThreshold()的值需要更改为“1.5”,而不是两个开发人员可以完成这些变化无需触及同一课程。

答案 1 :(得分:0)

看起来是一个很好的方法。

也许您想要封装interface SearchRequestBuilderConfigurer { public void configure(SearchRequestBuilder srb); } class DefaultSearchRequestBuilderConfigurer implements SearchRequestBuilderConfigurer { public void configure(SearchRequestBuilder srb){ srb.addField("*"); srb.addFilter("searchFilter"); } } class MatchSearchRequestBuilderConfigurer implements SearchRequestBuilderConfigurer { public void configure(SearchRequestBuilder srb){ srb.addFilter("matchFilter"); srb.addThreshold(0.5); } } 的配置逻辑以便

  • 更好的单元可测试性
  • 降低圈复杂度

例如:

public class SearchRequestBuilderFactory {

    public enum Type {
        SEARCH, MATCH
    }

    private Map<Type, SearchRequestBuilderConfigurer> type2Configurer = new HashMap<Type, SearchRequestBuilderConfigurer>();

    public SearchRequestBuilderFactory(){
        type2Configurer.put(Type.SEARCH, new DefaultSearchRequestBuilderConfigurer());
        type2Configurer.put(Type.MATCH, new MatchSearchRequestBuilderConfigurer());
    }

    public SearchRequestBuilder createBuilder(Type type) {
        SearchRequestBuilderConfigurer configurer = type2Configurer.get(type);
        if(configurer == null){
            throw new IllegalArgumentException("type " +  type + " is not supported");
        }

        SearchRequestBuilder srb = new SearchRequestBuilder();
        configurer.configure(srb);
        return srb;
    }

    private SearchRequestBuilder createSearchBuilder() {
        SearchRequestBuilder srb = new SearchRequestBuilder();
        srb.addField("*");
        srb.addFilter("searchFilter");
        return srb;
    }

    private SearchRequestBuilder createMatchBuilder() {
        SearchRequestBuilder srb = new SearchRequestBuilder();
        srb.addFilter("matchFilter");
        srb.addThreshold(0.5);
        return srb;
    }
}

封装配置逻辑后,您可以使用map而不是switch语句。

for (int i = 1; i < 11; i++) {
    if (Math.abs(number) < (j = Math.pow(10, i))) {
        System.out.println("Number of Digits : "+i);
        break;
    }
}

PS:您还可以使用facotry method pattern(又称虚拟构造函数)代替配置程序。