【问题标题】:remove duplication删除重复项
【发布时间】:2011-03-24 13:59:14
【问题描述】:

我有一个包含 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个也类似。这里有很多重复的代码。我觉得有更好的方法来实现这一点,但不知道如何。任何想法和建议表示赞赏。

谢谢, 莎拉

【问题讨论】:

  • 方法中实际使用了你的请求吗?
  • @Helper 是的。可以说是用在doAfterSuff();

标签: java


【解决方案1】:

使用类似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();

【讨论】:

  • 我有一个问题。当一个使用 RequestBuilder() 的客户端,他怎么知道他应该设置什么参数呢?以我帖子中的两种方法为例,我必须要求客户选择设置 5 个可能参数中的 2 个。我们如何确保客户端不会设置错误的参数?
  • 它设置任何它想要的(有'手边')。如果他的组合不够,抛出异常。
  • 在调用 build.这就是构建器的用途:许多可选参数(以减少伸缩构造函数)@bozo 你应该在构建器构造函数中设置强制参数
  • @fielding 当然,但我不知道有这样的 - 从上面的例子中没有一个必需的参数。
  • 我知道你知道,但提供的示例并没有显示出来。我认为这就是 sarah 所要求的:“......他怎么知道他应该设置什么参数?......”
【解决方案2】:
【解决方案3】:
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 模式,但因为你封装了一个算法,所以它似乎是 Strategy :)

Bozho 建议的是Builder 模式。

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

【讨论】:

  • 我不确定这是命令模式还是策略模式。您将算法(策略)解耦,但另一方面,这显然是一个封装的方法调用(命令)。也许有人可以说出为什么它是哪种模式。尽管该方法被立即调用,但我会说它的命令:)
  • @fielding 我想这是最重要的意图。但我只使用模式(有时不知道这是一种模式:)而且我不是那种理论模式的人。
【解决方案4】:

您可以将构建器对象传递给通用的 buildRequest 方法。由于不仅算法而且参数都不同,我将它们放入构建器中。我不认为这是一个很好的解决方案,但我想在这里展示一个命令模式:D(Extraneon 展示了如何解耦参数和命令)

    // 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();
    }

【讨论】:

  • 我喜欢你的解决方案。但我认为它将 BTypeBuilder() 暴露给客户端。这意味着客户必须了解所有不同类型的构建器。这不是“紧耦合”吗?
  • 您可以引入某种 Builder-Factory。静态工厂方法应该足够了,并且隐藏了所有不同的构建器。这取决于你在做什么。如果这是您的公共 api 的一部分,那么努力是合理的。如果不是,我不会走那么远。顺便说一句:如果您喜欢一个答案,请点赞;)
  • 哈哈...刚刚为您的帖子点赞!谢谢回答我的问题。 ;)
【解决方案5】:

除了其他答案之外,这也可能对您有用(如果您只想插入您的方法,而不是将参数用于“之前”和“之后”方法)

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;
        }
    });

【讨论】:

    【解决方案6】:

    只需将所有参数推送到映射中并将该映射作为参数发送,而不是发送长参数列表。

    【讨论】:

    • Hmmm..如果参数列表大小小于6(或4?),则可以。我认为实际上比将它们推入地图要好。您的用户如何知道要在地图中添加什么?
    • 这有什么帮助?您必须添加新的验证,因为您无法再判断地图是否包含合适的对象。最好引入某种 Person 类,它可以对姓名、性别和年龄进行分组。如果您有很多参数,请尝试引入工厂或构建器。但这与最初的问题无关。
    猜你喜欢
    • 1970-01-01
    • 2018-04-07
    • 1970-01-01
    • 2021-06-19
    • 2012-08-28
    • 2019-07-26
    • 2016-02-21
    • 2017-02-17
    相关资源
    最近更新 更多