/
设计模式

对象的不变性--一个关键的设计概念

24. 07. 2022

Obsah článku

不变性是构建稳定应用程序的最重要的设计概念之一。基本原则规定,一旦写下一个状态,以后只能读取,没有修改的可能。如果我们需要改变状态,我们必须创建一个新的实例,用另一个对象替换整个对象。

因此,数据类型可以非常粗略地分为两大类。

  • Mutable (单个实例内的可改变状态)
  • Immutable (不可改变的内部状态)

可变的对象可以在内部改变。也就是说,它们提供的操作,当以不同的组合调用时,会使我们得到不同的结果。不变性试图阻止这种行为。

定义

一个类是不可变的,恰恰是在实例创建后,实例数据不能以任何方式改变。

所以所有的数据都固定在构造函数中。所有标量数据类型也是自动不可变的。

一个主要的优势

用不可变的状态来设计应用程序,在执行操作的安全性方面提供了根本的优势。如果我们知道数据一旦写入,以后就不能被改变(突变),那么我们就可以,例如,非常可靠地进行调试,或者将应用程序分割成子函数,而不会有忘记任何中间状态的风险。

不变性的概念通常反对在对象/实体的属性中存储状态的原则,而是描述一种功能方法,即数据只是 "流 "过应用程序,例如像javascript那样。

从性能的角度来看,我们可以自动地说,不可变的对象可以无限期地被缓存,因为它们永远不会过时。

一个来自PHP的真实例子

到目前为止,PHP中最常用的不可变对象是DateTimeImmutable对象,它一旦创建就只能被格式化的方法调用。如果我们修改内部设置,该方法将返回一个新的实例。当使用一个使用所谓身份模式的ORM时,这个功能是至关重要的--例如,它允许我们保证当我们读取一个订单的创建日期时,它在应用程序中的所有地方都是一样的,参考的完整性不会被破坏。

一个可改变对象的具体例子。

$date = new DateTime('2021-05-14');
$tomorrow = $date->modify('+1天');
echo $date->format('Y-m-d'); // 2021-05-15
echo $tomorrow->format('Y-m-d'); // 2021-05-15

因为modify()方法只改变了DateTime对象的内部状态,并返回了相同的实例,所以打印的是同一个日期。因此,不存在所谓的内部状态的**变异,这是面向对象编程的基本行为。更新变量也改变了原来的变量。

现在是一个不可改变的对象的例子。

$date = new DateTimeImmutable('2021-05-14');
$tomorrow = $date->modify('+1天');
echo $date->format('Y-m-d'); // 2021-05-14
echo $tomorrow->format('Y-m-d'); // 2021-05-15

DateTimeImmutable对象是不可变的,这意味着它的内部状态永远不会改变。在调用modify()方法后,一个新的修改过的实例(也是不可变的)被存储在变量中。如果我们不把新值储存在变量中,以后就无法使用了。

原始价值从未被触及,并保持安全储存。

什么时候一个类应该是不可变的?

除非你有很好的理由让它变得可变,否则总是把一个类或函数写成不可变的。这将简化你未来的设计。

可变的类应该尽可能少的改变。我总是建议将不可变性的行为记录下来。

也许不变性的唯一缺点是,每次属性变化都必须创建一个新的实例,这对性能有轻微的影响。如果你的应用程序(像大多数应用程序一样)倾向于显示数据,而且改变数据的频率较低,那么以今天计算机的性能来说,这个缺点是相当不明显的。

哪些类型的数据应该是不可变的?

  • 所有标识符和唯一代码
  • 大多数ManyToOne和OneToOne数据库会话
  • 日期、时间、日历值
  • 循环浏览数组,我们想对每个元素做同样的操作
  • 间隔,成对,三倍,...
  • 几何图形、点、线、GPS坐标、物理地址等。
  • 日志和历史记录
  • 关于已处理的订单和大多数财务数据的信息
  • 关于相关实体的元数据

什么不应该是不可改变的。

  • 具有大量属性的大型对象
  • 来自数据库的大多数表格输出,如Doctrine实体
  • 从较小的部件逐步构建物体

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
4.