使用“混合”语言进行设计:面向对象的设计还是功能编程?


11

在过去的几年中,我喜欢使用的语言变得越来越“实用”。我现在使用的是一种“混合”语言:C#,F#,Scala。我喜欢使用与域对象相对应的类来设计我的应用程序,并使用使编码更容易,更简洁和更安全的功能功能(尤其是对集合进行操作或传递函数时)。

但是,当涉及到设计模式时,这两个世界会“冲突”。我最近遇到的特定示例是观察者模式。我希望生产者在创建或更改项目时通知其他一些代码(“消费者/观察员”,例如数据库存储,记录器等)。

我最初是这样“功能性地”完成的:

producer.foo(item => { updateItemInDb(item); insertLog(item) })
// calls the function passed as argument as an item is processed

但是我现在想知道是否应该使用更多的“ OO”方法:

interface IItemObserver {
  onNotify(Item)
}
class DBObserver : IItemObserver ...
class LogObserver: IItemObserver ...

producer.addObserver(new DBObserver)
producer.addObserver(new LogObserver)
producer.foo() //calls observer in a loop

两种方法的优缺点是什么?我曾经听过一位FP专家说,那里的设计模式仅是由于语言的局限性,这就是为什么功能语言很少的原因。也许这可能是一个例子?

编辑:在我的特定情况下,我不需要它,但是..您将如何以功能方式实现“观察者”的删除和添加?(即,您将如何实现模式中的所有功能?)例如,仅传递一个新函数?


演员呢?
kiritsuku 2012年

忘记了类以及所有那些OOPish没用的东西。您最好改为考虑模块(请参见SML和OCaml语言以获得灵感)。
SK-logic

@Antoras如果可以与基于Actors的方法进行比较,那就再受欢迎了:)
LorenzoDematté2012年

2
@ dema80,OCaml完全是多种范例。模块根本与功能编程无关。例如,纯命令式Ada中有一个先进的模块系统。而且,OOP赢得的所有名望实际上都应该归功于模块-OOP的所有好处仅仅是模拟模块功能的各种形式。您可以完全忘记所有这些类,而使用它们的语法来表示模块,而不是根据模块而不是OOP进行思考。顺便说一句,这正是Microsoft使用mscorlib所做的-那里没有太多的OOP,只有模块和名称空间。
SK-logic

1
我认为更好的问题是“以FP方式进行操作是否会使您失去清晰度或组织?”
djechlin 2014年

Answers:


0

这是两种不同方法的一个很好的例子,它们带有在调用对象关注的边界之外执行任务的概念。

虽然在此示例中很明显,您应该采用功能方法,但是通常,它实际上取决于被调用对象必须表现出的行为有多复杂。如果确实是一个复杂的行为问题,您会发现自己经常重新应用类似的逻辑,而函数生成器无法用来清楚地表达它,那么您可能想要进行类组合或继承,在这里您将在临时基础上具有更大的自由重用和扩展现有行为。

不过,我确实观察到的一种模式是,通常开发人员最初会采用功能性方法,并且只有在出现对更细粒度行为的需求时,他们才决定采用基于类的方法。我知道,例如,一旦好处和需求变得显而易见,Django就从基于函数的视图,模板加载器和测试运行器转变为基于类的视图,但是在此之前并没有。


我认为这个答案有点误导了。函数式编程不是(仅通过函数)编程。函数式编程也使用抽象,因此这里没有二分法。
2014年

“组合或继承,您将拥有更多的重用和扩展现有行为的自由”,您这样说是不是纯粹FP的核心优势之一。当您进行功能编码时,模块化,可组合性和可重用性自然会发生,这不是“ OOP事情”
sara

@FilipDupanović我指的是重用和扩展现有代码。纯函数可能是所有编程中最可组合的东西。您被写成好像无法在纯功能环境中管理复杂性。通过将简单的部分组成更大但仍然简单且不透明的部分来管理复杂性是FP的整个核心,许多人认为它比OOP更好。我提出了“不能缩放的功能性单线与没有缩放性的可靠OOP”之间的二分法。
萨拉

您说过FP在编写和重用代码方面逊色,并且当应用程序变得越来越复杂时,OOP或多或少总是“更好”的。我声称这完全是虚假和误导性的,因此我认为这值得一票。那真的是“纯粹的狂热”吗?我不会在这里进一步讨论这个问题,因为注释不适合此类扩展讨论。
2016年

5

该功能版本更短,更易于维护,更易于阅读,并且通常在几乎所有可以想到的方面都非常优越。

尽管要克服所有模式,但许多方法要弥补OOP中缺少的功能,例如观察者。这些在功能上要好得多。


我同意并且有相同的感觉。
罗伦佐·德马特(LorenzoDematté)2012年

我同意并且有相同的感觉。但是我对我的功能代码有点“作弊”:就我而言,这是我所需要的,但是如果我需要添加和删除“观察者”呢?我编辑了问题
LorenzoDematté2012年

5

您的“ FP专家”部分正确;许多OO模式都是做功能性工作的黑客。(他声称这就是很少有FP语言似乎充其量可疑的原因。)Observer和Strategy模式正在尝试模仿一流的功能。访客模式是一种模拟模式匹配的技巧。您IItemObserver只是变相的功能。假装它与其他任何需要某项功能的功能都不相同,那么您什么也买不到。

对象只是一种数据抽象。本文将有助于阐明该主题。对象可能有用,但是重要的是要认识到它们并不适合所有事物。没有二分法。只需为合适的工作选择合适的工具,而函数式编程绝不需要您放弃对象。除此之外,函数式编程不仅仅是使用函数。这也与最小化副作用和突变有关。


+1(IMO)是一个好答案。另外,感谢您提供该论文的链接:我已经读了一段时间,然后又丢失了它。现在,我又找到了它。
乔治

-1

我真的不能回答这个问题,因为我不擅长函数式语言。但我认为,只要您拥有的东西有效,您就应该较少关注方法。据我了解,只要您将来不添加更多侦听器或在执行过程中不更改侦听器,就可以在此处很好地跳过Observer模式。

我不同意设计模式弥补了面向对象语言中的“局限性”。它们在那里是为了充分利用OOP功能。多态和继承是功能,而非限制。设计模式利用这些功能来促进灵活的设计。您可以在OO中制作绝对非OO程序。您可以非常小心地编写一个完整的程序,其中包含无状态的对象,类似于FP。


1
“当然,您可以非常小心地编写一个包含不带状态的对象的完整程序,类似于FP。”当然,通过纪律,您也可以使用命令式语言来做同样的事情。:)在一般情况下,我不认为在设计patters的东西来弥补限制,但考虑访问者模式的情况下..
洛伦佐Dematté

另外,我也不关心代码:但是,我想在方法上与其他程序员面对面(据我所知,这就是programmers.se的用途,否则我会在SO上发表我的问题)
LorenzoDematté

每当您发现重复的模式时,都不过是语言和建模框架的严重限制。在理想世界中,根本不会有任何模式。
SK-logic

@ SK-logic:不幸的是,世界不是理想的,而现实世界却有规律。这就是为什么OO语言具有继承性,以实现可重复的代码而不必再次重写它们的原因。真实世界的对象具有状态,这就是为什么存在状态模式的原因
DPD 2012年

1
@ SK-logic:我很清楚某些语言是可编程的,有些语言也允许从类型系统强制执行效果。我的观点是,像“ OOP”一样,“模式”是一个令人遗憾的误解。模式是一些反复出现的类似,但不同的形式,即不承认一个统一的解决方案。有时,您可以使这些准重复消失-多方法使“访客” /“双重调度”变得多余。这并不意味着“所有模式都是缺陷的迹象”,因为这意味着现实世界是缺陷的。模式起源于体系结构,而不是软件。
Frank Shearar 2012年
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.