2010-08-03 228 views
5

我有一个类包含10个方法,除了一个关键事件外,它们的功能几乎相同。两个例子如下:删除重复


Public String ATypeOperation(String pin, String amount){ 
    doSomething(); 
    doMoreStuff(); 
    requestBuilder.buildATypeRequest(pin, amount); 
    doAfterStuff(); 
} 
 


Public String BTypeOperation(String name, String sex, String age){ 
    doSomething(); 
    doMoreStuff(); 
    requestBuilder.buildBTypeRequest(name, sex, age); 
    doAfterStuff(); 
} 
 

正如你从上面的方法看,他们是从调用由requestBuilder提供不同的方法除了类似。其余8个也类似。这里有很多重复的代码。我觉得有更好的方法来实现这一点,但不知道如何。任何意见和建议表示赞赏。

感谢, 萨拉

+1

您的请求是否真的在方法中使用? – helpermethod 2010-08-03 07:20:55

+0

@Helper是的。你可以说它用在doAfterSuff()中; – sarahTheButterFly 2010-08-03 07:23:40

回答

5

使用类似RequestBuilder,接受所有这些类型的参数:

public RequestBuilder { 
    // setters and getters for all properties 

    public Request build() { 
     doStuff(); 
     Request request = new Request(this); 
     doAfterStuff(); 
     return request; 
    } 
} 

然后

new RequestBuilder().setAge(age).setName(name).build(); 
+0

我在这里有一个问题。当使用RequestBuilder()的客户端时,他怎么知道他应该设置什么参数?以我的帖子中的两种方法为例,我不得不要求客户选择设置5个可能参数中的2个。我们如何确定客户端不会设置错误的参数? – sarahTheButterFly 2010-08-04 00:41:21

+0

它设置任何它想要的(有'在手')。如果他的组合不够,请抛出异常。 – Bozho 2010-08-04 06:13:46

+0

在调用构建之前,您可以通过其他方法调用在RequestBuilder构造函数和任何可选参数中传递强制参数。多数民众赞成在建设者:许多可选参数(减少伸缩式构造函数) @bozo你应该真的在建设者构造函数 – atamanroman 2010-08-04 06:16:09

2
interface RequestBuilder { 
    void doStuff(params); 
} 

public RequestBuilder getARequestBuilder() { 
    return new RequestBuilder() { 
    void doStuff(params) { 
     // impl.details 
    } 
    } 
}  

public RequestBuilder getBRequestBuilder() { 
    return new RequestBuilder() { 
    void doStuff(params) { 
     // impl.details 
    } 
    } 
}  

public String buildRequest(yourParams, RequestBuilder builder){ 
    doBefore(); 
    builder.doStuff(yourParams); 
    doAfter(); 
} 

我想,这就是所谓的Strategy模式。它看起来很像Command模式,但是因为你封装算法似乎是策略:)

什么Bozho建议是Builder模式。

我建议你一段时间浏览a list of patterns,或者购买Head First Patterns。真的很有趣的阅读。

+0

我不敢肯定,如果这是一个命令或战略模式。你解耦一个算法(策略),但另一方面,这显然是一个封装的方法调用(命令)。也许有人可以说出为什么它的模式。我会说它的命令,但立即调用该方法:) – atamanroman 2010-08-04 06:10:53

+0

@fielding我想这是最重要的意图。但我只使用模式(有时不知道它是一种模式),我不是一个理论模式的人。 – extraneon 2010-08-04 07:48:12

1

您可以在生成器对象传递给通用buildRequest方法。由于不仅算法而且参数也各不相同,所以我把它们放到了构建器中。我不认为这就是一个很好的解决方案,但我想在这里展示的命令模式:d(Extraneon展示了如何分离PARAMS和命令)

// call somewhere in the code: 
    Builder b = new BTypeBuilder(); 
    b.age = "20"; b.sex = "female"; b.name = "eve"; 
    String res = buildRequest(b); 

    Public String buildRequest(Builder builder) 
    { 
     doSomething(); 
     doMoreStuff(); 
     builder.build(); 
     doAfterStuff(); 
    } 

    // Command pattern 
    class BTypeBuilder implements Builder 
    { 
     String name, age, sex; 

     // Constructor here 

     void build() 
     { 
      // Do your stuff here 
     } 
    } 

    class ATypeBuilder implements Builder 
    { 
     String pin, amount; 

     // Constructor here 

     void build() 
     { 
      // Do your stuff here 
     } 
    } 

    public interface Builder 
    { 
     void build(); 
    } 
+0

我喜欢你的解决方案。但我认为它将BTypeBuilder()公开给客户端。这意味着客户必须了解所有不同类型的建设者。这不是“紧密耦合”吗? – sarahTheButterFly 2010-08-04 00:50:58

+0

你可以引入某种Builder-Factory。静态工厂方法应该足够,并隐藏所有不同的构建器。这取决于你在做什么。如果这是你的公共API的一部分,这个努力是合理的。如果没有,我不会走得这么远。 顺便说一句:如果你喜欢答案,upvote它;) – atamanroman 2010-08-04 06:23:00

+0

哈哈......只是upvoted你的文章!谢谢回答我的问题。 ;) – sarahTheButterFly 2010-08-05 03:59:28

0

除了其他的答案,这也可能对您有用(如你只想插件你的方法,不使用你的参数为“前”和“后”的方法)

interface Function0<R> { 
    R apply(); 
} 

public void performOperation(Function0<Void> operation) { 
    doSomething(); 
    doBeforeStuff(); 
    operation.apply(); 
    doAfterStuff(); 

} 

,那么你可以使用它像这样,

final RequestBuilder builder = new RequestBuilder(); 
    performOperation(new Function0<Void>() { 
     public Void apply() { 
      builder.buildATypeRequest("1234", "2445"); 
      return null; 
     } 
    }); 

    performOperation(new Function0<Void>() { 
     public Void apply() { 
      builder.buildBTypeRequest("1234", "2445", "1234"); 
      return null; 
     } 
    }); 
0

,而不是发送一个长PARAM eter列表只是将所有参数推送到地图中并将该地图作为参数发送。

+0

嗯..如果参数列表大小小于6(或4?),那就没问题。实际上,比我认为的推动它们更好。用户如何知道要在地图上放置什么? – sarahTheButterFly 2010-08-04 00:53:37

+0

这对什么有帮助?你必须添加新的验证,因为你不能再告诉地图是否包含拟合对象。引入某种Person类可能更好,它可以将姓名,性别和年龄分组。如果你有很多参数,尝试引进工厂或建设者。但这与最初的问题无关。 – atamanroman 2010-08-04 06:26:50