如何重构使用“策略模式”的大类?

3

问题

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

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()(在FooService内)这样的几个方法,它们都有自己的TransformerStrategy匿名实现,并随后调用getResponse()。你可以想象,这非常混乱,而且在调试时很容易让人感到困惑(即你正在进入getResponse(),然后突然回到了getFooForSomeFlow1())。

可能的解决方案

一个可能的解决方案(我想到的)是将这些不同的策略组织成一个“提供者”类,以某种方式将它们组合在一起。奇怪的是,这个类已经包含了这种类型的提供者类:
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. 还是有其他设计模式可以应用,可以更合适地简化这段代码?
谢谢

抱歉,当我意识到时就已经删除了。 - christopher
没问题,我已经删除了我的评论并更清楚地阐述了问题。 - Atif
5个回答

1
你的提供程序类实际上是一个工厂模式,这正是我要建议的。
通过将逻辑从getFooForSomeFlow1及其类似方法中移除,您创建了非常松散耦合的代码,这总是可取的。
出于个人偏好,我会拥有一个方法用于返回实例,并以Discriminator作为一个int值。这些int可以作为提供程序类中的静态常量变量,例如:
public static final int ABCTransformerStrategy = 1;

此外,将工厂类改为抽象类,可以避免每次需要使用时实例化该类,从而使代码更加简洁。

编辑

正如建议的那样,使用Enum是将值转换为它们所代表的具体类的一个更加理想和语义上正确的方式。

使用“枚举”来标识需要创建哪个具体实例是使用“int”的首选替代方案。 - nattyddubbs
同意。我现在会考虑到这个因素并回答您的问题 :) - christopher

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
}

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

0
如果您想提供一堆相关的对象,您可以随时使用“抽象工厂”。这不是一个简单的设计模式,但在这里是最合适的。
看看这个:抽象工厂

0

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


0

我尝试了irreputable的方法,并在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 类和内部类。
采用这种方法,现在调试和维护都更容易了,而且我们能够从代码中消除相当多的重复。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接