Eli*_*les 5 java oop refactoring design-patterns
我正在开发一个遗留的Java应用程序,它可以解决"水果"和"蔬菜"问题.它们在内部被视为不同的东西,因为它们没有共同的所有方法/属性,但是很多东西都完全类似于它们.
所以,我们有很多方法doSomethingWithAFruit(Fruit f)和doSomethingWithAVegetable(Veg v),即使用正确的doOtherStuffWithAFruit(Fruit f)/doOtherStuffWithAVeg(Veg v).这些非常相似,只不过用水果做事的方法只能用水果做方法,对蔬菜做同样的事情.
我想重构这个以减少重复,但我不确定实现这一目标的最佳方法是什么.我已经阅读了一些关于某些设计模式的内容,但我不知道它是否让我更清楚.(我可以识别我使用的代码中的一些模式,但我真的不知道何时应该使用模式来改进周围的事情.也许我应该阅读更多有关重构自身的内容......)
我在考虑这两个选项:
1.创建一个可以具有Fruit或Vegetable实例的类,并将其传递给方法,尝试最小化重复.它会是这样的:
public void doSomething(Plant p) {
// do the stuff that is common, and then...
if (p.hasFruit()) {
doThingWithFruit(p.getFruit());
} else {
doThingWithVegetable(p.getVegetable());
}
}
Run Code Online (Sandbox Code Playgroud)
这会让事情变得更好,但我不知道......它仍然感觉不对.
2.我以为对方选择是摆在水果和蔬菜的接口与通常给他们的东西,并用它来各地传递.我觉得这是更清洁的方法,虽然我需要使用instanceof和浇铸到水果/蔬菜,当它需要特定的东西.
那么,我还能在这做什么呢?这些方法的缺点是什么?
更新:请注意,问题有点简化,我正在寻找使用"植物"做事的方法,即主要"使用"它们而不是对它们做事的代码.话虽如此,我所指的那些类似方法不能在"Plants"类中,并且它们通常有另一个参数,如:
public void createSomethingUsingFruit(Something s, Fruit f);
public void createSomethingUsingVegetable(Something s, Vegetable v);
Run Code Online (Sandbox Code Playgroud)
也就是说,除了水果/蔬菜之外,这些方法还有其他问题,并且不适用于任何水果/蔬菜类.
更新2:这些方法中的大多数代码只从Fruit/Vegetable对象中读取状态,并根据相应的类型创建其他类的实例,存储在数据库中等等 - 从我对回答中的问题回答我认为这很重要.
您可以使用的另一个选项,或者可能将其作为解决方案的一部分包含在内,是询问使用者是否可以管理您传递给它的对象。此时,消费者有责任确保它知道如何处理您发送给它的对象。
例如,如果您的消费者名为 Eat,您将执行以下操作:
Consumer e = new Eat();
Consumer w = new Water();
if( e.canProcess( myFruit ) )
e.doSomethingWith( myFruit );
else if ( w.canProcess( myFruit ) )
w.doSomethingWith( myFruit );
.... etc
Run Code Online (Sandbox Code Playgroud)
但最终你会得到很多 it/else 类,所以你自己创建一个工厂来决定你想要哪个消费者。您的工厂基本上执行 if/else 分支来确定哪个使用者可以处理您传递的对象,并将使用者返回给您。
所以它看起来像
public class Factory {
public static Consumer getConsumer( Object o ){
Consumer e = new Eat();
Consumer w = new Water();
if( e.canProcess( o ) )
return e;
else if ( w.canProcess( o ) )
return w;
}
}
Run Code Online (Sandbox Code Playgroud)
那么你的代码就变成了:
Consumer c = Factory.getConsumer( myFruit );
c.doSomethingWith( myFruit );
Run Code Online (Sandbox Code Playgroud)
当然,在canProcess消费者的方法中,它基本上是一个实例或派生的其他函数,以确定它是否可以处理您的类。
public class Eat implements Consumer{
public boolean canProcess(Object o ){
return o instanceof Fruit;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,您最终将责任从您的类转移到工厂类来确定可以处理哪些对象。当然,诀窍是所有消费者必须实现一个公共接口。
I realize that my pseudo-code is very basic, but it is just to point out the general idea. This may or may not work in your case and/or become overkill depending on how your classes are structured, but if well designed, can significantly improve readability of your code, and truely keep all logic for each type self-contained in their own class without instanceof and if/then scattered everywhere.