什么时候在Scala中使用可变类和不可变类 [英] When to use mutable vs immutable classes in Scala

查看:82
本文介绍了什么时候在Scala中使用可变类和不可变类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于不可变状态的优点的文章很多,但是在Scala中是否有一些常见的情况使得偏爱可变类更有意义? (这是一个具有可变类的经典" OOP设计背景的人提出的Scala新手问题.)

Much is written about the advantages of immutable state, but are there common cases in Scala where it makes sense to prefer mutable classes? (This is a Scala newbie question from someone with a background in "classic" OOP design using mutable classes.)

对于像3维Point类这样的琐碎的事情,我获得了不变性的优点.但是,像Motor类这样的东西呢?它暴露了各种控制变量和/或传感器读数?经验丰富的Scala开发人员通常会编写此类不变的类吗?在那种情况下,速度"是否在内部表示为"val"而不是"var",并且"setSpeed"方法返回该类的新实例?同样,从传感器读取的描述电动机内部状态的每个新读数都会导致实例化电动机的新实例吗?

For something trivial like a 3-dimensional Point class, I get the advantages of immutability. But what about something like a Motor class, which exposes a variety of control variables and/or sensor readings? Would a seasoned Scala developer typically write such a class to be immutable? In that case, would 'speed' be represented internally as a 'val' instead of a 'var', and the 'setSpeed' method return a new instance of the class? Similarly, would every new reading from a sensor describing the motor's internal state cause a new instance of Motor to be instantiated?

在Java或C#中使用类封装可变状态的OOP的老方法"似乎非常适合Motor示例.因此,我很好奇,如果您一旦获得了使用不可变状态范例的经验,是否会甚至将Motor等类设计为不可变的.

The "old way" of doing OOP in Java or C# using classes to encapsulate mutable state seems to fit the Motor example very well. So I'm curious to know if once you gain experience using the immutable-state paradigm, you would even design a class like Motor to be immutable.

推荐答案

我将使用一个不同的,经典的OO建模示例:银行帐户.

I'll use a different, classic, OO modeling example: bank accounts.

这些几乎在地球上的所有面向对象课程中都得到了使用,并且您通常最终得到的设计是这样的:

These are used in practically every OO course on the planet, and the design you usually end up with is something like this:

class Account(var balance: BigDecimal) {
  def transfer(amount: BigDecimal, to: Account): Unit = { 
    balance -= amount
    to.balance += amount
  }
}

IOW:余额是 data ,而转移是 operation . (还要注意,传输是涉及多个可变对象的 complex 操作,但是该操作应该是 atomic 而不是复杂的……所以您需要锁定等.)

IOW: the balance is data, and the transfer is an operation. (Note also that the transfer is a complex operation involving multiple mutable objects, which however should be atomic, not complex … so you need locking etc.)

但是,那是错误.这并不是银行系统实际设计的方式.实际上,这也不是实际的现实世界(物理)银行的工作方式.实际的实体银行业务和实际的银行系统的工作方式如下:

However, that is wrong. That's not how banking systems are actually designed. In fact, that's not how actual real-world (physical) banking works, either. Actual physical banking and actual banking systems work like this:

class Account(implicit transactionLog: TransactionLog) {
  def balance = transactionLog.reduceLeft(_ + _)
}

class TransactionSlip(from: Account, to: Account, amount: BigDecimal)

IOW:余额是操作,而转移是数据.请注意,这里的所有内容都是不可变的.余额仅是事务日志的左折.

IOW: the balance is an operation and the transfer is data. Note that everything here is immutable. The balance is just a left fold of the transaction log.

还要注意,我们甚至没有以纯功能,不变的设计作为明确的设计目标.我们只是想对银行系统进行正确建模,而巧合地得到了一个纯功能,不变的设计. (嗯,这实际上并不是偶然的.现实世界中的银行如此运作是有原因的,它与编程具有相同的好处:可变的状态和副作用使系统变得复杂而令人困惑……在银行业中,这意味着钱消失了.)

Note also that we didn't even end up with a purely functional, immutable design as an explicit design goal. We just wanted to model the banking system correctly and ended up with a purely functional, immutable design by coincidence. (Well, it's actually not by coincidence. There's a reason why real-world banking works that way, and it has the same benefits as it has in programming: mutable state and side-effects make systems complex and confusing … and in banking that means money disappearing.)

这里的要点是,可以以完全不同的方式对完全相同的问题进行建模,并且根据模型的不同,您可能会发现琐碎的事情使得纯粹的不可变或非常困难.

The point here is that the exact same problem can be modeled in very different ways, and depending on the model, you might up with something which is trivial to make purely immutable or very hard.

这篇关于什么时候在Scala中使用可变类和不可变类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆