OOP是变得容易还是困难?[关闭]


36

几年前,当面向对象编程的概念被介绍给程序员时,它看起来很有趣并且编程更加简洁。OOP就是这样

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);

使用自描述名称更容易理解。

但是现在,具有数据传输对象,值对象,存储库,依赖注入等模式的OOP变得更加复杂。为了达到上述目的,您可能必须创建多个类(例如abstract,factory,DAO等)并实现多个接口

注意:我不反对使协作,测试和集成更容易的最佳实践


23
创建良好的软件体系结构一直很困难,而且(很可能)总是如此。
johannes 2012年

6
我将重命名addItemaddremoveItemremove。因为它更容易阅读。stock.add(item)stock.remove(item)。并且更多面向对象。
razpeitia 2012年

1
原始的OOP看上去几乎与您所显示的完全不同。OOP与语法无关,而是由Smalltalk推广的一种抽象。这并不一定证明您的观点是错误的,也不是前提存在缺陷。相反,它比您意识到的还要真实。
Konrad Rudolph 2012年

1
您正在按照逻辑比较苹果和橙子,那么命令式编程(即循环和条件条件)比我们今天拥有的所有东西都要简单。命令式编程是类/ OOP的构建块,而类/ OOP是设计模式的构建块。随着您的进步,事情变得越来越复杂,因为您正在解决更复杂的问题。
Lie Ryan 2012年

2
@LieRyan-我已经看到问题变得复杂,因为没有人能够通过简单的命令式编程来解决问题,而是在应该单独实现的简单命令式解决方案的基础上,在OOP之上使用设计模式来攻击它们。
mouviciel 2012年

Answers:


35

自成立以来,OOP本身并没有太大变化。已经探索了一些新角度,但是核心原理仍然相同。如果有的话,这些年来积累的集体知识使程序员的生活更轻松而不是更艰难。设计模式不是障碍。他们提供了从多年的经验中提炼出来的解决标准问题的工具箱。

那么,为什么今天您觉得OOP比开始使用OOP时要复杂呢?

原因之一可能是您所面临的代码变得更加复杂-不是因为OOP变得更加复杂,而是因为您已经在学习阶梯上有所进步,并且能够阅读更大,更复杂的代码库。

另一个原因可能是,虽然复杂度范例没有改变,但是普通软件项目的大小和复杂度可能会很好。不到二十年前,客户级手机已经具备了强大的处理能力,这在服务器上是开发人员的梦dream 以求的东西,因此,公众普遍期望,即使是最便宜的一次性应用,光滑的动画图形用户界面也可以使用,而入门级台式机的功能更强大与1980年代的“超级计算机”相比,自Smalltalk和C ++成立之初就提高了标准是很自然的。

还有一个事实,在现代应用程序中,并发和并行性是规范,而不是例外,并且应用程序经常需要在不同的机器之间进行通信,输出并解析整个协议库。尽管OOP作为组织范例非常出色,但它也有其局限性,就像其他范例一样:例如,它没有为并发提供很多抽象(大多数实现或多或少是事后才想到的,或者完全外包给了库) ,但这并不是构建解析器和转换数据的最佳方法。现代编程经常遇到OOP范式的局限性,而设计模式只能带您走这么远。(亲自,我认为我们需要设计模式这一事实表明了这一点-如果范式开箱即用地提供了这些解决方案,那么对于这些​​问题,它将更具表现力,并且标准解决方案将是显而易见的。没有设计模式来描述方法继承,因为它是OOP的核心功能。但是有一个工厂模式,因为OOP并未提供明显的自然方式来多态和透明地构造对象。)

因此,大多数现代OOP语言都融合了其他范式的功能,这使它们更具表现力,更强大,但也更加复杂。C#是最典型的例子:它有明显的OOP根,但是诸如委托,事件,类型推断,变量数据类型,属性,匿名函数,lambda表达式,泛型等功能源自其他范式,最著名的是函数式编程。


因此,设计模式增加了复杂性。含义设计模式不一定是OOP,而是为了增强OOP而添加的。
tunmise fasipe 2012年

@tunmisefasipe:不完全是。设计模式只是对标准问题的可靠解决方案。它们不是OOP的“附加”,而是结果。复杂性已经存在;设计模式只是提供解决方案。
tdammers

17

不,它变得更加工程化。没错,在SO C ++聊天中,我们经常开玩笑说我们在Java代码中看到的AbstractSingletonFactoryProxyBeanBridgeAdapterManagers。

但是好的代码并没有表现出这种特性。用好的代码,你仍然可以说

std::stack<int> s;
s.push(5);
s.pop();

4
从您的帖子中还不清楚,但是我认为Java C ++代码中的过度设计都是显而易见的。它本身不是这两种语言的属性,而是程序员的实践...两种语言都允许编写好的代码,尽管两种(IMO)都不适合:)很遗憾,Java框架确实很烂。
Andres F.

12
谈论过度工程,该线程是强制性的:describe.joelonsoftware.com/default.asp?joel.3.219431
安全

3
@AndresF。是的,但是您似乎并没有在C ++代码中得到太多,而在Java和.NET中却得到了:只需将MVVMVMMD设计模式msdn.microsoft.com/en-us/magazine/hh965661.aspx看成是一个示例,说明如何采用“简单代码”并在其上拍打一个设计模式,使其看起来更“容易”,然后在该设计模式上拍打另一个设计模式,因为原始模式并不像广告中那样简单。过度设计变得越来越普遍。
gbjbaanb 2012年

5
我会与“成为”有关。过度工程与工程一样古老。
2014年

4
@AndresF。在聊天中,我们特别反对Java,但的确,与C ++相比,Java 鼓励过度设计,因为它使它更容易负担(GC),并且流行的企业Java库已经普及了这种风格,正如您已经指出的那样。你自己
Konrad Rudolph 2012年

10

我要说的是,您提到的“复杂性”问题与OOP无关。它与分离关注点更多有关。

许多年前,我在一个系统上工作,其中域类负责从数据库中加载自身,例如

var userId = Request.QueryString["UserID"].ToInt();
var user = new User(userId);
user.Name = ...;
...
user.Save();

这是非常清晰的代码。理解这一点没问题。但是,问题在于对代码进行单元测试。即,如何在User不必从数据库中加载一个类的情况下对该单元进行单元测试?以及如何在不访问数据库的情况下测试此Web请求处理代码?根本不可能。

这就是为什么我们有一个类似于存储库的模式,以将处理域逻辑和用户的职责与实际加载和保存到数据存储中的功能区分开来。IOC有助于减少耦合,还可以使代码更易于测试等。

因此,如果我们回到您编写的示例,创建股票后您将如何处理它?将其保存在数据库中

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);
this.StockRepository.Add(stock);

在那里,完成了!OOP进展过程中没有任何运动表明应该更艰难。不幸的是,如果您选择使用OR映射器作为数据访问代码,则会遇到OR映射器对如何编写系统施加限制的问题。但这是另一回事。

如果您不熟悉这些模式,则可能需要学习一种新的编程风格。但是,这种编程风格绝不会比老式OOP编程难。


您知道建立存储库必须付出的努力。尽管设置完成后,它仍然可以重用。
tunmise fasipe 2012年

也许问题出在单元测试上,如果我们有更好的工具来测试整个系统(无论如何都需要测试)而不是测试很小的部分,那么我们的系统中的bug会更少吗?
gbjbaanb 2012年

2
@gbjbaanb:我们已经有了它,称为集成/功能测试。单元测试有一个不同但同样必要的目的
凯文(Kevin)

@gbjbaanb-我们已经拥有用于系统范围/验收测试的出色工具,例如Rails平台上的Cucumber。但是非常优秀的团队,只编写了很少的bug,但编写起来却很快,他们编写了许多单元测试,以及一些系统范围的测试。请参见“测试三角形”,例如,此处jonkruger.com/blog/2010/02/08/the-automated-testing-triangle
Pete

4

都不行 我们的问题并没有真正改变。可接受代码的标准已经提高。

为了达到上述目的,您可能必须创建多个类(例如abstract,factory,DAO等)并实现多个接口

你不必这样做。但是,如果不这样做,问题就会浮出水面;一直存在的问题。但是,程序员现在有足够的经验来识别这些问题并提供缓解问题的机制(如果需要)。我们会详细了解这些内容,并提出更好的解决方案(例如,请参阅-程序员对单例的看法)。

但是您还必须意识到,向程序员介绍OO(或与此相关的任何内容)往往会掩盖特殊情况。解释幸福的道路比较容易,而一旦初学者感到沮丧,就不用担心其余的事情了。没有银弹。所以是的,我想事情总是会显得困难时田园诗般的幻想被打破......


3

“ OO简介”示例比实际应用程序简单得多。您只需要一堂课即可达到上述目的。问题是它做得并不多。一些设计模式试图接近(例如ActiveRecord。)但是,最终,任何不平凡的示例都将具有多个类。那没问题。


还要注意,框架会随着时间而建立。是的,编程确实需要更多的知识。这也意味着人们可以在更短的时间内做更多的事情。
Jeanne Boyarsky 2012年

3

如今,使用OO的编程语言正在努力满足不断变化的复杂需求和环境。OO允许其采用者隐藏各种复杂性级别(以及其他功能),从而使编码变得更清晰,更易于构建和理解。但是,此功能并非总是开箱即用。在您的示例中,OO通过提供一种管理集合中项目的方法允许您向我隐藏一些细节,甚至可以使用“ AddItem”方法对其进行持久化。花费精力隐藏复杂性可能会导致易于使用和可重用的框架,从而使生活更简单。例如,许多ORM实现都允许您与数据库进行通信,而无需程序员编写SQL详细信息。这确实很强大,并且确实使开发人员更简单。

您所指的模式就是这样。它们应该使您的生活更轻松。但是,由您决定采用和调整它们。需要更多工作的事实仅仅是因为您可以获得更多好处。这就像为法拉利付出更多。如果您需要额外的费用,请为它们付费。因此,如果您决定构建可在多台服务器和不同的后端数据库上运行的可伸缩N层解决方案,则需要付出一定的代价。如果您的应用程序不需要这种复杂性,请忽略多余的部分,而转而使用最简单的解决方案来满足您的需求(KISS和YAGNI)。

因此,总的来说,我不认为OOP作为一个概念本身会变得越来越复杂,我们,OOP的用户可以选择以不同的方式使用它,这是一件好事。


明确点。我知道YAGNI。什么是KISS?
tunmise fasipe 2012年

2
@ tunmisefasipe,KISS是设计原则的简称。最初的单词是“保持简单(愚蠢)”(参考:en.wikipedia.org/wiki/KISS_principle),但是更客气的措词可能是“保持如此简单”。
NoChance 2012年

3
@tunmisefasipe-吻=保持简单,愚蠢。短语我重复我自己过来了,过来了,过来了,它仍然不似乎总是沉英寸
迈克尔Kohne

@MichaelKohne,我们都做!我认为能够简化事物是一门艺术。E = M C C以非常简洁的形式说了很多!
NoChance 2012年

3

简短的回答:是的,因为您要处理更棘手的问题。

长答案(强烈偏见):对我而言,设计模式通常表明某些范例在给定区域中存在问题。OOP模式处理OOP问题(较低级别的Java模式处理Java问题),FP模式处理FP问题等。

在编程期间,您可能有不同的优先级。您可能想要正确的程序,可能希望缩短上市时间,最快的程序,新员工的长期可维护性或即时可维护性。取决于灌木丛,您所处的位置将有很大不同-如果您要对电厂的控制器进行编程,则希望第一次正确地进行操作,而不是时不时地进行错误修复(“每次按下时都会发生崩溃Ctrl+Alt+Del吗?”)。如果您使用HPC,则逻辑可能相对简单,但是您希望尽快执行它,等等。此外,某些范例更适合某些问题(例如AI和逻辑编程,数据和关系数据库)。

在简单的情况下,OOP在某种程度上说是“太好了”,它是“模拟真实生活”的故事。例如,在关于OOP的第一本书中,我读到有类PersonEmployee并且Manager具有is-a关系。到目前为止还不错,但是如果将员工提升为经理该怎么办?

另一方面,其他范式的上课较难,例如具有不变变量的FP(有趣的是,有编程经验的人经常发现比那些以第一语言为母语的人更难学习)-但最终他们还是不比OOP难。测试纯函数很简单,在Haskell / Scala / ...中,您拥有可以为您生成测试的工具。

PS。是的-答案偏向于OOP,我承认在某种程度上它是对OOP的“反应”。OOP有其用途,但我认为它不是唯一的最终解决方案。

PPS。是的-使用设计模式-它们使OOP编程最终更简单。

PPPS。我使用OOP作为OOP命令式编程的同义词。


2

我认为更多的是文件和示例变得更加现实。

早期的OOP书籍(尤其是早期的Java书籍)提出了荒谬的应用程序编程简化视图。“借用10行Java程序从银行帐户中借钱”的示例总是特别烦人,因为我已经看到了这个简单任务运行到6000行COBOL代码的现实生活示例(而Java替换尝试在废弃之前运行了3500行)作为不可行!)。

幸运的是,面向对象的书籍现在倾向于承认现实生活的复杂性,并提供了如何处理它们的有用示例。

但是,如果您只想看一看如何在15行代码中进行银行帐户功能编程就可以了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.