无状态和不可变有什么区别?

16

我经常听到“无状态(Stateless)”和“不可变(Immutable)”这两个术语。例如,HTTP是一种无状态协议,而字符串对象则是不可变对象。但我很难理解它们之间的区别。当我创建一个无状态对象时,它不会在内部存储任何“状态”数据。如果我创建一个不可变对象,那么它就意味着它永远不会改变。

你的意思不是一样吗?

由于不可变对象不会改变,根据定义,它不能有状态。它永远都是什么样子的。如果一个对象没有状态,那么它就不能被改变(根据定义)。因此,所有无状态对象都是不可变的,而所有不可变对象都是无状态的,不是吗?

可变的无状态对象或不可变的有状态对象有什么例子?

4个回答

8

这里的上下文很重要,有两个不相关的概念。

"HTTP是一种无状态协议" 意味着每个请求对于其他请求都没有隐含的知识,包括同一客户端发送的任何先前请求。这与像FTP或SMTP这样的协议不同,在这些协议中,建立连接,然后发送不同的命令——每个命令/请求都与同一客户端/连接“关联”。当然,通过 cookie 和跟踪 URI 甚至可以添加回状态/跟踪 ——但重点是每个请求在 HTTP 协议中都是“新的”和“独立的”。

"字符串是一个不可变对象" 意味着该特定对象的数据将始终以每种可观察方式相同(这也意味着可观察属性不能被更改)。有些纯粹主义者可能会认为它有比这更深层次的影响,但实际上它只是关于可观察属性的问题——当不可变对象可以“包含”可变对象时,问题变得更加复杂。

(是的,严格来讲,一个没有允许数据或状态的对象不能被更新,因此是“不可变的”。然而,再次强调,“上下文很重要”,在大象身上谈论牙齿或老虎鼻子上的象鼻有些奇怪。)
编辑:两者之间的区别
一个没有状态的对象是无状态的。所有无状态的对象都是不可变的(因为没有什么可以改变);这是一种自我证明的技术性问题。一个对象可以有状态并且仍然是不可变的——然而,一个有状态的对象(无论是否不可变)不再被认为是无状态的。如链接答案的评论所述:“[一个不可变对象]有且只有一个状态”,即初始状态。
— 来自我的评论

好的,也许HTTP不是一个好的例子。但在对象的上下文中,我仍然听到术语“无状态对象”https://dev59.com/S2kw5IYBdhLWcg3wqMU0。或者也许这个人在这个上下文中真正意味着“不可变的”? - Laurent Bourgault-Roy
4
一个没有状态的对象是无状态的。所有无状态的对象都是不可变的(因为没有东西可以改变);这是一种既定的技术术语。一个对象可以具有状态并且仍然是不可变的 - 然而,具有状态的对象(无论是否不可变)不再被视为无状态。根据链接答案上的评论:“[不可变对象] 有且只有一个状态”,即初始状态。 - user166390
1
啊,我现在明白了。可以这样说,无状态对象是不可变对象的一个子集,具有相同的有趣属性(可以在线程代码中安全使用,保证将来不会更改等),但也具有一些自己的附加属性(例如,在同一类的任何实例上调用的方法都保证始终返回相同的结果,因为它们没有状态来影响结果)。 - Laurent Bourgault-Roy
所有状态无关的内容都是不可变的,但反之则不然,因此不可变性是状态无关性的超集,或者说...稍微调整一下 (不可变(状态无关)) - icc97

6

不,它们的意思并不相同。

一个不可变对象永远无法改变。这并不意味着该对象中包含的数据不能指示状态。它只是意味着如果您想表示状态的更改,则需要创建一个新对象。

无状态意味着没有状态。


好的,这些概念实际上没有关联,它们互不影响。因此,一个没有字段,只有方法的“无状态”类并不意味着与所有字段都是只读的“不可变”类具有相同的保证。谢谢! - Laurent Bourgault-Roy
没错。一个不可变对象可以拥有状态(存储数据),但是该状态永远不会改变。一个无状态对象不能存储任何数据。我现在明白了什么是不可变集合! - Robert Mark Bram
1
一个对象怎么可能没有状态呢?即使你实例化最基础的对象,它也肯定会有某些状态。就拿Java中最简单的对象来说,它也一定会包含某些状态,比如对类的引用等等。在任何编程语言中,真正的无状态对象是否真的存在呢? - toniedzwiedz
@c++中的class stateless {}是一个例子。在Java的情况下,你可以将其解释为“忽略JVM的簿记”。 - Caleth

3
我认为在某些情况下它们是相同的,但我们关注略有不同的方面。
当人们说“无状态”意味着没有状态时,这让我感到好笑。当然,从某种角度来看,它具有一些状态,例如无状态服务可以由对象的复杂图形(依赖注入)支持。问题在于网络协议对“状态”的含义略有不同:它是取决于先前请求/响应的东西。但是,不可变的服务也不会根据以前的调用而改变,根据定义。
“无状态”并不总是与HTTP协议相关,我们可以使用相同的术语来讨论您闪亮的OOP代码中的服务对象中的设置器。在这里,您可以看到这两个术语实际上是相同的:不可变服务是无状态服务,反之亦然。
然而,我觉得将值对象称为“无状态对象”很尴尬。听起来很糟糕。
总结:就服务而言(网络或OOP,无所谓),我认为这些术语是可以互换的。
仅举例说明:
interface Logger
{
    public function logWarning(string $message);
    public function logError(string $message);
}

无论我们调用多少次 logWarning 或者 logError,调用的顺序也没有关系。因此,我们可以称之为 "无状态服务"。

但是这个服务也没有像 changeFileName() 那样的设置器或任何变化器 -> 它是一个不可变的服务/对象。

可变性会使对象有状态。 状态会使对象可变。 在服务的背景下,这些术语是相互依存的。


1

它们绝对不是一样的。

不可变对象永远不会被改变。不可变对象的状态永远不会被修改,别名不会对不可变对象造成任何影响,因此不需要为不可变对象进行别名控制,尽管可能需要别名控制来证明对象实际上是不可变的。

而无状态意味着没有状态。 HTTP 被称为无状态协议,因为每个命令都是独立执行的,没有任何关于之前命令的知识。它基于请求范式,在该协议中,通信通常在 TCP/IP 协议上进行。


有趣的是,如果我没记错的话,TCP 会维护一些状态(你必须保持连接才能发送数据)。这意味着你可以在有状态的协议之上实现无状态的协议? - Laurent Bourgault-Roy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接