出版于

创业

带有状态的编程:价值观和实体

开发人员非常了解程序中可变状态的危险。一个值从您下方变化,弄乱了正在进行的计算。屏幕上的两个不同的位置表面上是基于相同的信息,彼此之间并不一致。应用程序崩溃是因为在适当的时间没有更改值。

编程的功能风格基于不变的值和函数,这些价值和函数构建了新值而不是突变现有值,因此由于在所有物体都可以变形时管理状态的复杂性,因此变得非常流行。但是,假设我们发现具有可变状态的编程有用。例如,我的经验主要是用本机工具在移动应用程序开发中由大多数开发人员实践。然后,主要问题成为我们如何管理该状态以保持我们的程序可理解的。

价值观和实体

我发现有用的观点是将程序操纵的对象分为两种,实体。一个值在概念上类似于原始类型,即不可变的对象,其结构化值仅仅是其零件的总和,没有隐藏内容。相反,每个实体都是一个独特的对象,即使与具有完全相同状态的实体。作为一个实体具有独特的身份,其状态可能是可变的。

两种状态及其特征

这种观点将平等与可变性相结合,但我认为不需要其他可能性。具有独特身份的不变对象可以简单地是包含唯一标识符的值。在我的经验中,具有基于州平等的可变对象只是要求麻烦。

诸如C#和Swift之类的语言在语言层面上具有某些分离,将类型分离为结构(值)和类(实体)。但是它们并非一路走来,因为两者都包含了其实体类型的过度平等,从而可以定义基于非身份的平等。我觉得这是从“一切都是实体”的语言中保留的,并且在适当的价值分开语言中没有位置。这“身份有一种状态”的方法要好得多,但我们不能总是在Clojure编程。

我在上表中使用了“功能”和“面向对象”的术语,因为这是基于一种基于一种的编程样式对我的感觉。功能样式基于值,从现有值纯计算中构建新值,而面向对象的样式基于具有内部状态的不同实体,其外部接口修改了内部状态。本文的其余部分将集中在基于实体的面向对象样式上,依靠可变状态,因此我不会对纯粹的功能风格说更多。

状态

既然可变状态的大野兽已经被推到我称之为实体的这些东西中,让我们看一下如何管理它。我在实体中将状态分为两种形式,内部和外部。内部状态的管理方式并不重要,因为这是该实体本地的,并且可以包含在足够小的区域中,通常可以理解。

对于外部状态,这应该是由实体暴露的东西是有意义的。大多数情况下,最好不要简单地直接将内部状态直接作为外部状态暴露,而是为外界提供更有意义的东西。甚至仅揭露可以在实体上执行的调用,该实体的实施取决于内部状态,但没有暴露任何特定状态。

不变有助于保持实体的状态可管理。不变性只是在实体状态的不同部分中占据的属性。例如,在代表购物车的实体中,总价应该是单个物品价格的总和减去任何应用折扣。尽管一个实体正在修改自身,但可能会暂时违反不变性,但是外部观察者应始终看到不变的持续存在。

我在外部状态中使用了上表中的“可观察”一词。对我来说,这是正确管理应用程序状态的必要条件。其他实体必须有可能观察实体状态的变化并对这些变化做出反应。在状态应用中,状态部分永远不会完全独立,因此保持完整的应用状态一致性需要同时修改其中的许多部分。

依赖性

可观察的状态和对其变化的反应引入了一个实体及其状态的概念,具体取决于另一个实体的状态。在内部,实体可以包含对其依赖其他实体的引用。他们的状态可以取决于其他实体的状态。因此,有两种状态:基本状态和衍生状态,其中衍生状态是其他状态的组成。

我发现管理此问题的一种好方法是将实体的可观察状态表示为价值。之后,派生状态可以定义为其依赖状态的纯函数。从本质上讲,这是电子表格的工作方式,这是一个非常有用的概念模型,可将完整的应用状态理解为由独立的基本状态和衍生状态依赖的部分组成的概念模型。实体可能包含其他实体作为内部状态,但这些包含的实体永远不会被视为外部状态。

为了正确执行此操作,编程语言或环境需要支持某种形式的数据绑定。衍生状态是通过与其所有依赖性结合的结合来定义的,并具有纯粹的函数来构成它。这样,系统保证整个应用程序中的所有状态始终是一致的。从理论上讲,这也可以通过观察者模式来完成,但是随着观察者模式从更新中分配状态的定义,实际上,当关系变得复杂时,可以忘记一些必要的更新来衍生状态。

Redux架构显示类似的思维。状态变化是通过采用现有状态和改变状态的行动的纯函数进行的。Redux本质上只有一个实体,即商店,它简化了派生状态管理。当与诸如React之类的东西结合在一起时UI是应用状态的纯粹功能,国家管理的复杂性大大降低。

在鼓励多重风格的平台中,衍生状态的管理并没有真正支持所有语言本身或其库的支持。数据绑定通常是通过修改事件来处理的,例如,在钻石依赖性方案中无法很好地发挥作用:实体状态顶部的状态取决于Middle1和Middle2的实体状态,这两者都取决于实体底部的状态。修改状态的正确顺序为底部 - >(Midder1,Midder2) - >顶部,其次是任何电子表格,但是基于修改事件的系统将执行底部 - > midder1-> top,其中新的顶部状态根据Middle1的新状态但Middle2的旧状态计算,从而导致不一致。

钻石依赖场景的一个例子

对于大型状态而言,在很小的变化时,根据从头开始重建所有状态并不是最好的主意。例如,如果州代表商店服务的整个产品目录,则增加一个产品是一个很小的变化,不应触发大规模的重新计算。在这种情况下,我通常包括其他变更事件。更改事件本质上只是先前状态和当前状态之间的区别,并且它具有足够的信息,因此可以修改任何派生状态以匹配新的依赖性状态。因此,当第一次使用派生状态创建实体时,会执行完整的计算,但是之后,对派生状态进行了修改,以反映通过变更事件传达的更改。

- -

- -

在建造自己的东西方面变得更聪明。关注该初创公司的每月读者 +800万次读者和 +760k关注者。

获取中型应用betway娱乐官网

一个说“在应用商店上下载”的按钮,如果单击,它将带您到iOS App Store
一个说“获取它,Google Play”的按钮,如果单击它,它将带您到Google Play商店
jaakko kangasharju

Fosanis GmbH的后端工程师。Python,数据库,侧面iOS的迅速。一些数据科学/机器学习。计算机科学博士学位。

Baidu