3

问题

我有一个大类(大约 1500 LOC),它使用不同的“策略”将数据从一个对象转换为另一个对象。我这里有那个类的代表:

public class FooService implements FooProcessing {
    FooRequestTransformer fooRequestTransformer;
    AnotherService anotherService;
    InstanceVar1 iVar1;
    InstanceVar2 iVar2;    
...

这个类使用了一个接口(类外部):

interface TransformerStrategy {
    public FooRequest transform(FooResponse response);
}

哪个被传递到这个方法中(在 FooService 类中):

private FooResponse getResponse(FooResponse fooResponse, TransformerStrategy transformerStrategy) {
    FooRequest fooRequest = transformerStrategy.transform();
    fooResponse = anotherService.bar(fooRequest); 
    return fooResponse;
}

入口点在这里,它使用该getResponse()方法并TransformerStrategy匿名创建:

public List<Foo> getFooForSomeFlow1(Param1 param1, Param2 param2, ...){
    FooResponse fooResponse = anotherService.baz(fooRequest);

    TransformerStrategy myTransformerStrategy = new TransformerStrategy() {
        public FooRequest transform(FooResponse fooResponse) {
            fooRequestTransformer.transform(param1, param2, iVar1, iVar2) 
        }
    }

    FooResponse fooResponse = getResponse(fooResponse, myTransformerStrategy);
    ...//other code
}

现在的问题是:有几种方法,如getFooForSomeFlow1()(inside FooService),它们都有自己的匿名实现,TransformerStrategy随后调用getResponse()。正如您可以想象的那样,这非常混乱,并且在您调试时令人困惑(即您正在进入getResponse(),然后突然又回到了getFooForSomeFlow1()

可能的解决方案

一种可能的解决方案(想到的)是将这些不同的策略组织成一个“提供者”类,该类将以某种方式将它们组合在一起。奇怪的是,这个类已经包含了这种类型的 Provider 类:

protected class StrategyProvider {
    public ABCTransformerStrategy newABCTransformerStrategy(FooRequestTransformer transformer, Param1 param1, Param2 param2) {
        return new ABCTransformerStrategy(transformer, param1, param2);
    }
}

protected class ABCTransformerStategy implements TransformerStrategy {
    protected FooRequestTransformer transformer;
    protected Param1 param1; 
    protected Param2 param2;

    //...constructor here

    //...overridden transform method as above
}

在其中一条评论中说,“出于测试目的,将匿名类转换为内部类”。然而,他们只改变了其中一个人,而留下了其余的人。所以就像他们开始重构过程并在中间停止。

所以,我想我可以完成重构并将所有匿名类移动到内部类,然后最终将这些类移出StrategyProvider到外部类。问题是“将匿名转换为内部”增加了更多样板文件(见ABCTransformerStrategy上文;我必须将所有数据传递给构造函数),我不确定通过这个重构过程可以获得多少。

我有两个问题:

  1. 我应该继续这种方法吗?
  2. 或者是否有另一种我可以应用的设计模式更合适并真正简化此代码?

谢谢

4

5 回答 5

1

根据您提供的代码示例,它表面上很复杂。为什么不简单

public List<Foo> getFooForSomeFlow1(Param1 param1, Param2 param2, ...)
{
    FooResponse fooResponse = anotherService.baz(fooRequest);

    FooRequest  fooRequest = fooRequestTransformer
                                 .transform(param1, param2, iVar1, iVar2); 

    FooResponse fooResponse2 = anotherService.bar(fooRequest);
    ...//other code
}

除非还有其他事情你没有向我们展示。

于 2013-03-06T21:14:33.873 回答
1

您的提供者类实际上是一个工厂模式,这正是我要建议的。

通过将逻辑移出getFooForSomeFlow1和类似的方法,您创建了非常松散耦合的代码,这始终是可取的。

只是出于个人喜好,我会有一种方法,用于返回实例,该方法将int值作为鉴别器。这些 int 可以是提供程序类中的静态最终变量,例如:

public static final int ABCTransformerStrategy = 1;

此外,通过将 Factory 类设为 Abstract,您将无需在每次需要使用该类时实例化该类,从而使代码更加简洁。

编辑

正如所建议的,使用Enum是将值转换为它们所代表的具体类的一种更可取且语义正确的方法。

于 2013-03-06T21:12:01.503 回答
0

将每个方法转换为它自己的类(方法对象模式,即方法即对象),这与原始重构的去向类似。如果您需要集中访问所有这些方法 - 作为对象,请实现一个抽象工厂。根据您的描述,听起来您正在从一种类型转换为另一种类型,因此请让抽象工厂接受两个Class参数并将类组合的适当方法作为对象实例返回给调用者。

于 2013-03-06T21:22:17.930 回答
0

我尝试了不可靠的方法并在该方法上尝试了“内联方法” getResponse(),但它内联了一些重复的代码(这就是我们getResponse()首先将重复的代码提取到其中的原因)。我应该在我的问题中澄清说,其中的代码getResponse()比我展示的要多。
至于制作工厂,我无法证明在类中引入更多样板和 LOC 是合理的,特别是因为我必须将大量数据传递给工厂方法和/或内部类。

我们所做的是,我们用这样的方法包装了匿名内部类:

private TransformerStrategy createTransformerStrategyWithABCValues(Param1 param1, Param2 param2, IVar ivar, IVar1 ivar2) {
    return new TransformerStrategy() {
        public FooRequest transform(FooResponse response) {
            return FooRequestTransformer.transform(
                    param1,
                    param2,
                    iVar1,
                    iVar2);
        }
    };
}

现在调用方法如下所示:

public List<Foo> getFooForSomeFlow1(Param1 param1, Param2 param2, ...){
    FooResponse fooResponse = anotherService.baz(fooRequest);
    TransformerStrategy myTransformerStrategy = createTransformerStrategyWithABCValues(param2, param2, iVar1, iVar2);
    FooResponse fooResponse = getResponse(fooResponse, myTransformerStrategy);
    ...//other code
}

在这样做的过程中,我们发现 5 个策略有一些重复,因此我们能够将其缩减为 3 个策略。我们摆脱了 StrategyProvider 类以及提供的内部类。

使用这种方法,现在调试/维护变得更容易了,并且我们能够从代码中减少相当多的重复。

于 2013-03-11T18:11:40.537 回答
0

如果你想提供一堆相关的对象,你总是可以使用Abstract Factory. 它不是一个简单的设计模式,但却是最适合你的。

看看这个:抽象工厂

于 2013-03-06T21:10:56.420 回答