哲思片段 | 设计中的变与不变

古希腊哲学家巴门尼德认为:“人的思想和言语都有一个载体,如果你在这一时间和另外一个时间想到或者谈到同样一件东西,那就说明这件东西在这段时间内没有变化,如有变化的话,你说的就不是同一件东西。”

这让我想起对象的实例。在面向对象设计中,默认情况下并没有约束类的实例是否为可变,这意味着我们可以通过某种方式改变实例的状态。这体现了实例的可变特征。然而,若是站在内存的角度观察实例,则又不然。无论它在内存中存储的状态如何变化,该实例的对象标识依旧是保持不变的。显然,变与不变是相对的。

切换到DDD的命题中,所谓“实体”就是那种具有唯一的可识别可跟踪ID的对象。这个ID并非程序语言在内存中为它分配的对象标识,而是从领域角度来看,由设计者为其识别,由创建者为其分配,因而具有领域语义。实体的状态当然是可变的,然而实体ID在这个实体的生命周期中却是不可变的。

与之相对的是值对象。在DDD中,强调将领域对象严格区分为实体和值对象。一个指导原则是,当你无法分辨某个领域对象究竟是实体还是值对象时,应优先将其建模为值对象。这有助于我们更好地利用值对象的不可变性。

不可变的对象能够更好地维护,因为你不用操心它的值变化,也无需追踪变化的轨迹。不变性天生支持并发。这就衍生出面向对象设计中的Immutable模式。例如Java和C#中的String类型,皆为Immutable模式的实现。

可若放在函数式编程中,这种模式就显得有些可笑了。尤其在纯函数式编程的世界里,任何东西都应该是不变的。

这种不变意味着只要它存在,就不可修改,而且恒古不变。这种追究变化背后的不变性,一直是古希腊哲学乃至科学的基本原则。物质是否永恒不变,在哲学中一直是引人深思的命题或假设;但在函数式编程中,它几乎被证明了。例如,在Haskell中,对List的任何操作,即使调用++对List进行合并,返回的都是全新的List对象,原有对象不会有任何变化。

罗素在《西方哲学简史》中写道:

有的神秘主义者认为永恒并不是指时间上的永久,它是独立于时间之外的,无前无后、无因无果,也没有逻辑可循。

我觉得函数式编程追求的不变性,可以划入这个范畴。

赫拉克利特说:“人不能两次踏进同一条河流”。这是赫拉克利特终极的哲学观,即万物随时在变。软件系统就是这样一条河流,它无时无刻不在变化,正如水不断的流动,需求也总是在变化。但若抛开原子裂变、放射衰变的科学原理,我们似乎也可以将组成整条河流的每一滴水,看做是不变的基本组成要素。这个要素就是Monad中的Identity(幺元或单位元)。这个Identity表达了单一、恒等的概念,例如Int类型中加减法运算半群(SemiGroup)中的Zero,就是一个Identity,因为半群中的任何元素a与Zero结合,依然是元素a本身。

水是如何组成一条河流的呢?这取决于组合子(Combinator)的设计与组合。只要我们找到万物的基本要素,继而设计出各种组合子,就可以演绎出世间不同的物。例如水滴虽可以组合为河流,却也可以组合为橙汁,只要我们加入橙子的另一个组合子即可。这就是面向组合子(Combinator Oriented)的设计思想。显然,它与面向对象的设计哲学背道而驰。

以哲学史观之,函数式思想更符合古典的朴素哲学观。在古希腊哲学家中,泰勒斯认为世界的元素为水,阿那克西美尼认为世界的元素是气,赫拉克利特认为世界的元素是火,而恩培多克勒则糅合了这些思想,认为世界的元素有土、气、火、水四种。而观中国古代哲学,则有五行学说认为宇宙万物都由金木水火土五种基本特性的运行和变化所构成。

不论构成万物的基本元素为何,这种哲学观不正是函数式编程的设计观吗?

原文发布于微信公众号 - 逸言(YiYan_OneWord)

原文发表时间:2014-09-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hightopo

HT图形组件设计之道(四)

825
来自专栏用户3030674的专栏

Android 性能优化——之图片的优化

 在Android性能优化中,我们会发现占内存最大的和对性能影响最大的往往是图片资源,其次是控件资源。相对来说,其他的资源的影响会小一点。这里我就先对图片资源的...

471
来自专栏逍遥剑客的游戏开发

Bullet的最小化功能封装

1223
来自专栏HT

HT图形组件设计之道(四)

在《HT图形组件设计之道(二)》我们展示了HT在2D图形矢量的数据绑定功能,这种机制不仅可用于2D图形,HT的通用组件甚至3D引擎都具备这种数据绑定机制,此篇我...

1745
来自专栏IT笔记

Dubbo负载均衡配置

在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。 负载均衡扩展 (1) 扩展说明: 从多个服务提者方中选择一个进行调用。 (2) 扩...

2945
来自专栏张俊红

Python面向对象编程

1715
来自专栏java 成神之路

高亮标红

2728
来自专栏运维小白

18.8 LVS调度算法

LVS调度算法 轮询 Round-Robin 简称:rr 最简单的也是最容易理解 用户请求过来,均衡的分发到rs上 加权轮询 Weight Round-R...

1777
来自专栏新工科课程建设探讨——以能源与动力工程专业为例

9.1 汽包锅炉水位自动控制

1,水池Pool,底面积为1m2,初始液位为1m,水的初始容积为1m3,目标水位(targetLevel)控制在1.2m,实际液位(actualLevel)受入...

720
来自专栏Golang语言社区

组件-实体-系统 (ECS \CES)游戏编程模型

一般来说,我们实现游戏实体都是采用面向对象的方法进行编程。每一个实体都是一个对象,并且需要一个基于类的实例化系统,允许实体通过多态 来扩展。但是,这样的方法,往...

1032

扫描关注云+社区