我正在参加「启航方案」
前文中咱们用数据转化的思维,手把手地对事务需求进行了拆解,简略得令人惊讶!毫无争议,这是数据转化思维的劳绩!
咱们也讲了,依照一贯的惯例办法,在数据相关与打通上,咱们无能为力,无法发挥数据转化思维(原因请回忆前文)。可是看看事务需求拆解,获得了实实在在的优点,咱们又迫切希望数据转化思维,能够在数据相关与打通上大展拳脚。
既然惯例办法不可,那咱们就走出一条新的光亮之路来。让咱们拨去蒙蔽双眼的惯例旧思维,用清澈明达的双眼,好好看看这已到面前的光亮。
让我来告知你怎么办。
先从一个小小的示例开端(先睹为快)
咱们运用面向未来的 rainforest-js 来实现这看似不可能完成的使命。
先别多想,只是看,稍后会解说。
Step.1
const MyStruct = typedef({
fieldA: string,
fieldB: string,
fieldC: string,
})
看这个数据结构,依照数据转化的思维,咱们应该令 fieldA
>fieldB
>fieldC
,来看看怎么做。
Step.2
ruledef(
MyStruct,
'rule1',
{
fieldA: true,
},
(self) => {
self.fieldB = self.fieldA + '.org'
}
)
ruledef(
MyStruct,
'rule2',
{
fieldB: true,
},
(self) => {
self.fieldC = self.fieldB + '.cn'
}
)
咱们界说了两个规矩,rule1 用来将 fieldA
转化为 fieldB
;rule2 用来将 fieldB
转化为 fieldC
。接下来,咱们用真实数据验证下。
Step.3
const myself = typeinit(MyStruct)
myself.fieldA = 'rainforest-js'
console.log(myself.fieldB) // rainforest-js.org
console.log(myself.fieldC) // rainforest-js.org.cn
完美,数据转化都是正确的。
一个合理的解说
Step.1
咱们界说了一个数据结构的类型描绘 MyStruct
,包含三个字段。
Step.2
依据需求 fieldA
>fieldB
>fieldC
,咱们这样来考虑:
-
fieldA
是最初始的输入,应该由用户输入。 -
fieldB
是从fieldA
转化而来的,所以,咱们就为类型描绘MyStruct
界说一个规矩。规矩的行为是:当fieldA
发生改变时,自动将其转化为fieldB
。 -
fieldC
同上。(发散考虑:字段更多会怎么?)
规矩,从姓名上,你就能感受到它的强壮、强制、不可违反,必定不可能犯错!
咱们再来考虑下,既然是规矩,那么规矩的触发,是必定不需求用户自动控制去触发的。就像,你不需求自动触发万有引力,它一直都在,不可违反。
所以,咱们只是在 rule1 中描绘了:当 fieldA
发生改变时,将其转化为 fieldB
。咱们严厉践行了数据转化思维,表达清楚了数据:从哪里来,到哪里去。
Step.3
依据类型描绘 MyStruct
,初始化了一个实例 myself
,然后为字段 fieldA
赋值,终究打印出希望的成果。
fieldB
和 fieldC
的值是自动转化来的,咱们什么也没做,没有自动控制,仅仅是为 fieldA
赋值了最初始的输入数据。
就这?当然不!
上述的解说连皮裘都算不上,只是让你初窥数据转化思维的一丢丢影子,在脑海中先有个轮廓,大概能看得懂代码就行了。
不过,上述虽然简略,但却道出了数据转化思维编程的中心规律。值得时常回味,刻入魂灵。
另一个示例
咱们略微变一变,引入子结构体后,看看是怎样的。
const OtherStruct = typedef({
fieldA: string,
/* ... */
})
const MyStruct = typedef({
other: OtherStruct,
result: string,
})
然后在最外层上界说规矩。(为什么不在内层结构体上呢?)
ruledef(
MyStruct,
'rule3',
{
other: {
fieldA: true,
}
},
(self) => {
self.result = self.other.fieldA.toUpperCase()
}
)
接下来,验证成果。
const myself = typeinit(MyStruct)
myself.other.fieldA = 'rainforest-js'
console.log(myself.result) // RAINFOREST-JS
咱们再变一下。
const myself = typeinit(MyStruct)
myself.other = typeinit(OtherStruct, {
fieldA: 'rainforest-js',
})
console.log(myself.result) // RAINFOREST-JS
成果也是正常的。为什么呢?
很简略,由于 other
整个都变了,那么 other.fieldA
必定也发生改变了。
咱们持续变。将 other
赋值为空。
const myself = typeinit(MyStruct)
myself.other = null
猜猜会发生什么?会报错抛出异常吗?
答案是:什么也不会发生,也不会报错。
由于,规矩 rule3 里明确地描绘了需求调查的是 other.fieldA
,而 other(null)
是必定不包含 fieldA
的。所以,规矩 rule3 是不会履行的。(由于不符合规矩呀,对不对。)
这样,就赋予了咱们一种轻松的能力,只需在界说规矩时,描绘清楚待调查的子结构字段即可,规矩内部不需求判断子结构是否为空,放心大胆地直接 .
就完事儿了。(发散考虑:假如结构层级很深呢?)
数据相关与打通
看懂上述内容后,答案其实现已呼之欲出了。
正如代码里所见,咱们很简单就能够把不同的数据结构进行相关。如:MyStruct
->OtherStruct
,只需求在一个数据结构中引证另外一个数据结构就行了。
把数据相关后,咱们也能很简单把数据打通了,让数据实现转化。只需求界说一个规矩,描绘清楚需求调查的字段,然后写完数据转化的进程。
假如数据相关引证的结构层级很深,那也没有关系。关于规矩而言,不管多深都能感知到,由于这是规矩,没错儿,这便是规矩!
关于规矩,可能刚开端不太简单理解,或感到别扭,别担心,习气就好。
一个好的诀窍是:把思维从 if … then … 转化到 when … then …
再解说清楚一点
咱们这样来想象一下:
一个程序的中心进程其实是 A
>B
>C
…Z
,便是数据转化的进程。假定,中心相邻 M
和 N
两个要害点相隔很悠远(便是说,在传统代码中,两个很难相关起来,分属八棍子撂不着的不同模块),没有关系,先在数据结构中树立相关(界说两个字段引证 M
、N
),然后界说规矩,调查其间的 M
并将之转化为 N
(便是如此简略)。重复此进程,终究就能将 A
转化为 Z
。
这其间,咱们再次验证了数据转化思维的有效性。每个规矩,都依赖于输入 M
,然后转化为输出 N
。
一起,也展示出了一个风趣的隐秘现象,不知道你们发现没有?
便是,每两个要害点都能看作一个彻底独立的小规矩(和其他规矩不相关)。整个程序的数据转化链 A
>B
>C
…Z
,之所以能正常作业,是由于终究这条链能够串起来!可是,风趣的是,由于每两个要害点转化的规矩都是独立的,那么就意味着,整条链也能够彻底打散,分开来写,不必纠结先后顺序,甚至都不需求关心怎么串起来。由于,整条链的规矩都写完后,这条链自然而然就串起来了,国际真奇妙。(发散考虑:那么还需求纠结先写什么后写什么吗?以及由谁来写吗?)
注:唯一能让两个规矩发生相关的其实是要害点(数据字段),而不是规矩本身。所以在 规矩1 没有写完的情况下,你依然能够先写 规矩2。由于要害点(数据字段)一直就在数据结构上静静地躺着。
一个完好的开发流程
我先假定你读懂了上面的全部,假如不明白请提问出来。
上一篇文章中,咱们对事务需求进行了拆解,现在咱们要把这全部彻底、完好地串起来,看看是怎样的编程体验。
第一步,面临事务需求和流程图,把用到的数据结构写出来。彻底不需求考虑任何逻辑部分。
第二步,再次看一眼流程图,不必分析逻辑,只看流程分支节点,把条件和导向的成果找出来。它们应该都是数据结构上的字段。然后依据找出来的输入字段和输出字段,写规矩。
第三步,重复第二步或第一步。
终究,由用户输入初始数据。
这便是用数据转化思维的完好编程体验。
数据转化思维是一个强壮的奥秘咒语,只需对着流程图上的逻辑进程多念几遍,就能干掉它。现在,请用力在心中铭记,毫不犹豫地大声吟诵出来,不要扭扭捏捏,大大方方地告知身边的朋友们吧。
未来的编程办法(一)
未来的编程办法(二)
面向未来的 rainforest-js