首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函数式程序设计+领域驱动设计

函数式程序设计+领域驱动设计
EN

Stack Overflow用户
提问于 2013-02-11 13:53:38
回答 2查看 6.1K关注 0票数 16

函数式编程促进了不可变类和引用透明性。

领域驱动设计由价值对象(不变)和实体(可变)组成.

我们应该创建不可变的实体而不是可变的实体吗?

让我们假设,项目使用Scala作为主要语言,如果我们处理并发性,我们如何才能将实体写成案例类(不可变的so)而不冒陈旧状态的风险?

什么是好做法?保持实体可变(var字段等)并避免了案例类的大语法

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-11 14:33:25

您可以有效地使用Scala中的不可变实体,并避免易变字段和从可变状态派生的所有bug的恐怖。使用不可变的实体可以帮助您实现并发性,不会使事情变得更糟。您以前的可变状态将成为一组转换,它将在每次更改时创建一个新的引用。

然而,在应用程序的某一级别上,您将需要一个可变的状态,否则应用程序将是无用的。这样做的目的是在程序逻辑中尽可能地把它推高。让我们以一个银行账户为例,它可以因为利率和取款或存款而改变。

您有两种有效的方法:

  • 公开可以修改内部属性的方法,并在这些方法上管理并发性(实际上很少)。
  • 您使所有类都是不可变的,并且用一个可以更改帐户的“管理器”包围它。

由于第一个非常简单,我将详细介绍第一个。

代码语言:javascript
复制
case class BankAccount(val balance:Double, val code:Int)

class BankAccountRef(private var bankAccount:BankAccount){
   def withdraw(withdrawal) = {
       bankAccount = bankAccount.copy(balance = bankAccount.balance - withdrawal)
       bankAccount.balance
   }
}

这很好,但是天哪,您仍然在管理并发性。Scala为您提供了一个解决方案。这里的问题是,如果您共享对后台作业的BankAccountRef引用,则必须同步调用。问题是您正在以一种次优的方式进行并发。

并发的最佳方式:消息传递

如果在另一方面,不同的作业不能在BankAccount或BankAccountRef上直接调用方法,而只是通知它们需要执行一些操作呢?那么您就有了一个Actor,这是Scala中最受欢迎的并发方式。

代码语言:javascript
复制
class BankAccountActor(private var bankAccount:BankAccount) extends Actor {

    def receive {
        case BalanceRequest => sender ! Balance(bankAccount.balance)
        case Withdraw(amount) => {
            this.bankAccount = bankAccount.copy(balance = bankAccount.balance - amount)
        }
        case Deposit(amount) => {
            this.bankAccount = bankAccount.copy(balance = bankAccount.balance + amount)

        }

    }
}

这个解决方案在Akka文档中得到了广泛的描述:http://doc.akka.io/docs/akka/2.1.0/scala/actors.html。其思想是通过向Actor的邮箱发送消息来与Actor通信,并按接收顺序处理这些消息。因此,如果使用此模型,则永远不会存在并发缺陷。

票数 15
EN

Stack Overflow用户

发布于 2013-02-11 14:29:28

这是一个不像你想的那么具体的意见问题。

如果你真的想要拥抱FP,我会选择所有域对象的不可变的路径,而不会将它们放在任何行为上。

也就是说,有些人将上面的服务模式称为服务模式,在这种模式中,行为和状态总是分开的。这在OOP中避免了,而在FP中则是自然的。

这也取决于您的域名是什么。有状态的东西,比如UI和电子游戏,OOP要容易得多。对于硬核心后端服务,如网站或REST,我认为服务模式更好。

除了经常提到的并发性之外,我还喜欢两种非常好的东西,即不可变对象具有更高的缓存可靠性,而且它们也非常适合分布式消息传递(例如,基于amqp的protobuf ),因为它们的意图非常明确。

同样在FP中,人们通过创建一个“语言”或“对话”,也就是DSL (建筑商、Monads、管道、箭头、STM等)来对抗变到不变的桥。这使您能够进行变异,然后将其转换回不可变域。上面提到的服务使用DSL进行更改。这比你想象的更自然(例如SQL是一个“对话”的例子)。另一方面,OOP更喜欢拥有可变域,并利用语言现有的过程部分。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14813416

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档