我有一个大类(大约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
}
现在的问题是:有{em>几个方法,例如getFooForSomeFlow1()
(在FooService
内),它们都有自己的TransformerStrategy
匿名实现,随后调用{ {1}}。你可以想象,这是非常混乱的,并且在调试时会让人感到困惑(即你正在进入getResponse()
,然后突然之间你又回到了getResponse()
)
一种可能的解决方案(想到这一点)是将这些不同的策略组织到一个“提供者”类中,该类将以某种方式将它们组合在一起。奇怪的是,这个类已经包含这种类型的Provider类:
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
;我必须将所有数据传递给构造函数)并且我不确定我通过这样做获得了多少重构过程。
我有两个问题:
由于
答案 0 :(得分:1)
您的提供者类实际上是Factory pattern,这正是我建议的。
通过将逻辑移出getFooForSomeFlow1
和类似方法,您创建了非常松散耦合的代码,这总是令人满意的。
仅仅出于个人偏好,我会有一个用于返回实例的方法,它将int
值作为判别器。这些int可以是提供者类中的静态最终变量,如:
public static final int ABCTransformerStrategy = 1;
此外,通过使Factory类为Abstract,您将无需在每次需要使用它时实例化该类,从而使代码更加清晰。
修改
正如所建议的那样,使用Enum
是一种更为理想且语义正确的将值转换为它们所代表的具体类的方法。
答案 1 :(得分: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
}
除非有其他事情发生,否则你没有向我们展示。
答案 2 :(得分:0)
如果您想提供一堆相关对象,可以随时使用Abstract Factory
。它不是一个简单的设计模式,但最适合你。
看看这个:Abstract Factory
答案 3 :(得分:0)
将每个方法转换为自己的类(method object pattern,即method-as-object),这与原始重构的去向类似。如果您需要集中访问所有这些方法,那么对象实现abstract factory。从您的描述中可以看出,您正在从一种类型转换为另一种类型,因此,使抽象工厂接受两个Class
参数,并向类型组合返回适当的方法作为对象实例。
答案 4 :(得分: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类以及提供的内部类。
使用这种方法,现在调试/维护起来更容易一些,我们能够从代码中删除相当多的重复。