很高兴,banq来回复,并提出看法。

下面继续说说我的认识和观点。

首先,状态是任何对象都有的,不存在无状态的对象,这是因为,对象都是有生命周期的,既然有生命周期,则在这个生命周期中,必然有某个时刻的状态。

只不过,区别是,一般人认为,从头到尾,贯穿了整个生命周期,而值不改变的,就不是状态。如果只处于生命周期中,某个时间段的,那么就是有状态,其实,如果统一起来看,无非是这个时间段的长度不同,本质上都是有状态的。

举例:

李白的name,可以这么说:
李白从生下来取了名字叫李白后,到他死,这个时间段,都叫李白。

希拉里.克林顿的name,可以这么说:
从希拉里嫁给克林顿后,她的名字,叫做:希拉里.克林顿。在此之前,她跟他父亲姓,结婚之后,跟她老公姓。

年龄,肯定是随时间不断变化的,有状态的。

性别,看似无状态,其实,可以这么描述:变性人,在变性之前,是男,在变性之后,是女。

职称,某某人,在某某职称考试通过之前,是什么职称,在考试通过之后,是什么职称。

婚姻状况,某某人在20岁结婚之前,是未婚,在20岁结婚之后,是已婚,在45岁离婚之后,是离异。

所以,我们可以看到,任何一个属性,其实都可以像我这样改写为一个属性名,加上一个时间段的限定。

所以,其实完整的声明应该是:

private String name [时间段]
private String sex [时间段]

如此这般,才是完整的。

其实从哲学上说,因为对象有生命周期,所以它有一个时间段,有一个时间段,必然有一个在这个时间段的状态。

只不过,如果一般这个时间段的状态,对人来说,没用,那么就把这个看成是一个无状态的,而实际上,它还是有状态的。

例如那个结婚主题中的司机,可以是无状态的对象,因为他对于结婚主题来说,无关紧要。但是,这个司机其实肯定是有状态的对象。

归纳一下,属性值其实是对象在某一个时间段的状态表示。
既,属性值,本质上是一个状态表示。


如上所述,面向对象编程,本质上是面向有状态编程的。

一个问题:数据库中到底存什么?

通常,人们会把程序运行后的结果的值,存入表中。
并且,随着程序的运行,去做所谓的增删改查。

或者,是把一个对象,持久化到数据库中去。

这其实在面向对象中,都不对。

存入数据库的应该是,基于时间的,对象的状态改变的log(就像日志)
数据库应该记录的是所有时间上的对象状态,而不是结果(“结果”只是一个状态)。即,数据库应该是记录的完整的“历史”!当需要结果的时候,结果是从对象状态上(历史上)重建出来的。

因为时间是一直往前走的,时间没法回头,所以,状态是一直递增改变的。

例如,朱元璋,
小时候,叫放牛娃,
童年叫,小叫花子,
青年,叫教主,
登基后,叫皇帝。

所以,如果我们要一个朱元璋,那么你是要哪个时期的朱元璋呢?
对于一般人来说,都是要当了皇帝后的,但是,我们不排除,要一个童年时候的。

那么对数据库来说,其实也只有2个操作,新增,查询。

删除,其实是生命周期结束,update,其实是随着时间的往前进行在某个时刻的状态改变。

当我们要得到一个通常的程序运行结果的时候,不应该直接把数据库中的记录读取出来,显示给客户。而是应该通过:主题,party,时间(时间起点),这3要素综合生成的一个惟一的类似数据库主键ID的这样一个ID,去串起来整个主题事件,并取出某个时间点的状态值,组合成结果,返回给用户。

听起来很复杂?其实很简单。

归纳一下,数据库应该是记录所有对象的所有状态历史。
结果从历史中重建,并呈现给用户。



编程模型中,比较麻烦的如:并发,异步调用,分布式处理,事务,等等,其实
都可以通过这个三要素组成的主键ID,串起来,并进行回放,回放验证。

三要素组成的主键ID:时间,参与者party,主题,这3者形成一个惟一的主键ID。给这个ID取个名字吧,暂且叫做“3要素ID”。

其实抽象来理解就是,每个案件,是每个案件,各个都不相关。例如,你去淘宝上下单买双拖鞋,他去亚马逊上买盒CD,这是两件事,是两个案子。

即:
是不同的人(party),在某个时间(时间有可能是相同的),做的某件事情(主题事情也可能是相同的,例如有2对新人,同时进行婚礼)。

这样很好区分,即便是2对新人在同一时间举行婚礼,人们也绝对不会搞错,因为参与者party不同。

“3要素ID”确保了,世界可以异步,分布式的,独立运行,从而保证了任何一个事情,都是可以重建的。

这也很好理解,任何一个案子,破案后,都可以重建整个案子的各个环节。


如何进行重建,回放?

我们不是依据时间来进行回放的,而是依据“3要素ID”进行回放。

系统要可控,必须有一定的边界范围,领域对象的属性、方法而要是边界范围内的即可,业务模型的抽象应该可以用业务语言来描述的,不一定要统一在固定的几个元素上面。

2012-09-07 00:37 "@wangcity"的内容
例如那个结婚主题中的司机,可以是无状态的对象,因为他对于结婚主题来说,无关紧要。但是,这个司机其实肯定是有状态的对象。 ...

这个讲法很有意思,非常类似实体和值对象区别,我个人一直将实体看成状态对象,因为在当前场景,也就是你说的主题中,它是需要被分辨的,只有状态才能标识分辨。

而对于不关心的对象,无需分辨,就是值对象,比如画画这个场景,你只关心画,至于红颜色笔有两个相同的,你不必区分关心,但是在另外场景中,这两个红颜色笔是有状态的。

其他贴待我慢慢欣赏。

2012-09-07 01:00 "@wangcity"的内容
归纳一下,数据库应该是记录所有对象的所有状态历史。
结果从历史中重建,并呈现给用户。 ...

我的理解是:数据库应该记录所有改变对象状态的事件历史,也就是Event Sourcing,并通过事件追溯重现当时状态。

这样同时也带来大数据,只有记录所有事件,才有真正大数据,否则现有的大数据,只不过是最后结果的大数据,而不是能够重现过程的大数据,用处不大。
[该贴被banq于2012-09-08 15:37修改过]

2012-09-07 01:00 "@wangcity"的内容
主题,party,时间(时间起点),这3要素综合生成的一个惟一的类似数据库主键ID的这样一个ID,去串起来整个主题事件,并取出某个时间点的状态值,组合成结果,返回给用户。 ...

关于这个3要素ID,我也很认同,为什么呢?
因此从四色原型来看,表达的是什么人Party在什么场合场景下实施什么活动事件,四色原型认为再复杂的业务也可以划分到这四种颜色,如同颜色的三原色,也就是说,这四色组成标识业务的最小单元,又能彼此区分,它不就是3要素ID吗?

好了,有了这个基本单元ID,那么从其中我们也许能发现领域模型实体,什么是实体,彼此能够区分,有唯一标识的的对象。而这3要素会产生一个标识状态,通过这个状态可以对应到这3要素。这两方面一会合,一碰撞,显然状态就是实体的状态啊,因为状态是一个宾语,它一定要有主语的,不可能没有主体的状态啊,那个主体就是实体。

楼主是从另外一个角度阐述业务统一语言,而我从四色原型+DDD+DCI来与你会合,个人发现我们能够相互打通,这不会是巧合,而极可能都是揭示领域同一个旋律,只不过表达方式不同。

相关主题:
危险的DDD聚合根

业务建模:CQRS应用场景

通俗易懂,受益匪浅!

原来事件模式改变了传统的软件体系架构,传统的数据库表保持的是状态变化的最终值,event保存的是事件记录。

传统模式无法通过重演得到历史数据,所以导致了事务回滚机制的产生,而事件机制无需事务,重演就是事务回滚。

总的来说很不错,但有很多我持有不同观点。

一、先事务这一点,我的观点是别拿事务来描述事件或事情,那是多余的。因为事件事情包含过程,而事务是为状态变化而生的,而函数过程是无态。为了过程而长久打开事务,那是一直以来的问题所在。

我们要注意“因为我,所以我”和“因为那个我,所以这个我”的区别。没有分清“我”在时间上的区别,才会导致用事务来覆盖整个逻辑过程。

最容易证明过去事务是一个问题的例子就是“统计”——没有对过去做任何改变,只是得到新的东西(跟生孩子差不多)。

其实或者说,你的“事务”不是真正的事务,因为事务本身就有定义的。你说的事务更像是事件。


二、还有现实中是存在无态对象的,通常见得最多的是定义,例如词语,这类东西有着名字即意义的作用。而论坛上说得最多的是值和值对象。你说之所以“无态”是因为“不改变”,我可以这么认为:你认为存在改变,是因为你把两个无关的状态拉到一起,而有态对象中拉起这桥梁的是id。举个例子:你眼前有一朵红色的花,闭上眼睛再睁开,眼前有一朵黄色的花,你这么认为,花从红色变成黄色,但若果事实是有人把花换了呢(只考虑颜色差异)?所以说这不是本质上有态,而是人认为它有态。

想坚持观点的,请先考虑如下两个问题:1、“1”的状态是什么?2、状态的状态是什么?


三、回滚(或回溯),其实只要严格按照不变性设计方案走的话,回滚(或回溯)是天然的——只要在持久化前失败了就不会保存失败的值,而且也不存在再计算的情况出现。


@banq

对于banq提到无状态的案例太少,其实是一直都存在,只不过我们没有那样去想而已。例如把数据库看作IO,或者把它当作一个集合来输入,那么逻辑处理过程就是最适合函数化的地带。很多时候都是一些先入为主的概念,使到我们没办法转过来。