最近有人看了我的代码,并评论说这太过程了。需要说明的是,他们看到的代码并不多 - 只是一个部分清楚地概述了应用程序中采取的逻辑步骤。
if(downloadFeeds(ftpServer, ftpUsername, ftpPassword, getFtpPathToLocalPathMap())) {
loadDataSources();
initEngine();
loadLiveData();
processX();
copyIds();
addX();
processY();
copyIds();
addY();
pauseY();
resumeY();
setParameters();
}
然后,这些不同的方法会创建一大堆不同的对象,并根据需要在这些对象上调用各种方法。
我的问题是 - 是一段显然驱动你的应用程序的代码,例如,指示程序编程,如果是这样,那么实现相同结果的更多OO方式是什么?
非常感谢所有评论!
答案 0 :(得分:7)
嗯,这段代码所在的类显然有太多的责任。我不会把所有东西隐藏在一个外观中,但不是所有的东西都与一些ftp引擎,数据源和位于单个神对象(反模式)中的其他实体相关,应该有一个业务流程,HAS所有这些实体。
所以代码看起来更像是:
if(downloadFeeds(ftpServer, ftpUsername, ftpPassword, getFtpPathToLocalPathMap())) {
datasource.load();
engine.init();
data.load();
engine.processX(data);
data.copyIds()
foo.addX();
engine.processY();
// ...
}
数据源,引擎和所有其他组件可能会被注入您的业务流程,因此a)测试变得更容易,b)交换实现得到简化,c)代码重用是可能的。
请注意,程序化的代码并不总是坏的:
class Person {
public void getMilk()
{
go(kitchen);
Glass glass = cupboard.getGlass();
fridge.open();
Milk milk = fridge.getMilk();
use(glass, milk);
drink(glass);
}
// More person-ish stuff
}
虽然该代码显然是程序性的,但它可能没问题。它完全清楚这里发生了什么,不需要任何文档(马丁的干净代码鼓励像这样的代码)。只需记住单一责任原则和所有其他基本OOP规则。
答案 1 :(得分:6)
ConnectionData cData = new ConnectionData(ftpServer, ftpUsername, ftpPassword, getFtpPathToLocalPathMap());
if(downloadFeeds(cData)) {
MyJobFacade fc = new MyJobFacade();
fc.doYourJob();
}
MyJobFacade.java
public class MyJobFacade {
public void doYourJob() {
/* all your do operations maybe on different objects */
}
}
通过Facade Pattern的方式
http://en.wikipedia.org/wiki/Facade_pattern
答案 2 :(得分:6)
我的问题是 - 是一段显然驱动你的应用程序的代码,例如,表示程序编程,
无法确定此代码片段是否“太程序化”。
那些的调用都可以是当前对象上的实例方法,可以在单独的对象上运行,也可以在当前实例的实例变量上运行。这些将使代码OO,至少在某种程度上。
如果这些方法是static
,那么代码确实是程序性的。这是否是一件坏事取决于方法是否正在访问和更新存储在static
字段中的状态。 (从名称来看,他们可能需要这样做。)
如果是,那么实现相同结果的更多OO方式是什么?
很难说不看其余的代码,但图片中似乎有一些隐含的对象;例如
engine
其中一些可能需要是类(如果它们不是类)......但是哪些取决于它们在做什么,它们有多复杂等等。通过将静态变量转换为实例变量,可以使类(无论出于什么原因)变得“更加OO”的状态。
其他答案建议特定的重构,摆脱所有全局变量,使用依赖注入等等。我的看法是,没有足够的信息来判断这些建议是否会有所帮助。
仅仅使应用程序“更多OO”并不是一个有用或有价值的目标。您的目标应该是使代码更具可读性,可维护性,可测试性,可重用性等。使用OO是否会改善问题取决于代码的当前状态,以及新设计的质量和重构工作。简单地采用OO实践不会纠正糟糕的设计,或者将“坏”代码变成“好”的代码。
答案 3 :(得分:4)
我将采用不同的方法对此进行批评,而不是它是否“过于程序化”。我希望你觉得它有点用处。
首先我没有看到任何函数参数或返回值。这意味着您可能正在使用各种全球数据,如果您愿意,可以通过以下许多理由来避免这些数据:Are global variables bad?
其次,我没有看到任何错误检查逻辑。假设resumeY因异常而失败,也许问题是在resumeY中,但它也可能在pauseY或更高的loadDataSources中更高,并且问题仅在稍后显示为异常。
我不知道这是否是生产代码,但它是在几个阶段进行重新分解的良好候选者。在第一阶段,您可以通过并使每个函数返回布尔成功与否,并在每个函数的正文中检查已知错误情况。在进行了一些错误检查后,通过传入函数args并返回结果数据,开始摆脱全局数据;你可以让你的函数在失败的情况下返回null值或转换为异常处理,我建议例外。在此之后考虑将单个部件单独测试;例如所以你可以测试downloadFeeds与数据处理功能分开,反之亦然。
如果您经历并进行一些重新分解,您将开始看到明显可以模块化代码并改进代码的地方。 IMO你应该更少担心,如果你是OOP足够多,更多关于你是否可以1.有效地调试它,2。有效地测试它3.在离开后理解它并在6个月后回来维护它
这个回复结束了很长时间,我希望你发现它的一部分很有用。 : - )
答案 4 :(得分:3)
是。您的方法不返回任何值,因此从它看起来它们在全局变量上运行的片段。它看起来像是教科书程序编程。
在一个更为面向对象的方法中,我希望看到类似的东西:
if(downloadFeeds(ftpServer, ftpUsername, ftpPassword, getFtpPathToLocalPathMap()))
{
MyDatasources ds = loadDataSources();
Engine eng = initEngine(ds);
DataObj data = loadLiveData(eng);
Id[] xIds = processX(data.getX());
Id[] newXIds = xIds.clone();
data.addX(newXIds);
Id[] yIds = processY(data.getY());
Id[] newYIds = yIds.clone();
data.addY(newYIds);
pauseY();
resumeY();
someObject.setParameters(data);
}
保
答案 5 :(得分:2)
以下是我学会区分的方法:
您的代码对您有“程序性”的标志是当一个班级有多个职责时(请参阅Single Responsibility Principle上的此链接)。看起来所有这些方法都被一个对象调用,这意味着一个类正在管理一堆责任。
更好的方法是将这些职责分配给可以最好地处理它们的现实世界对象。一旦正确委派了这些职责,就可以实现可以有效驱动这些功能的软件模式(例如Facade模式)。
答案 6 :(得分:1)
这确实是程序编程。如果你试图让它更多OO,我会尝试这些组合:
基本上,只是试着将您的计划视为让一群员工为您工作,并且您需要为他们分配职责。 (PM为我做了这个,然后DM做了这个结果)。如果您对一名员工承担全部责任,他或她将被烧毁。
答案 7 :(得分:0)
我同意它看起来过于程序化。使其看起来不那么程序化的一种明显的方法是让所有这些方法都成为类的一部分。 Erhan的帖子应该让你更好地了解如何分解它: - )
答案 8 :(得分:0)
我最好的建议是Clean Code: A Handbook Of Agile Software Craftsmanship
这是一本优秀的代码风格最佳实践书籍。有点长,但值得花时间。