在分层理念中,一种通用的分层思想,是将应本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net用分为“数据层”“逻辑层”“表现层”,在未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。每层内,我们又可以细分。你可能会想,“分原创内容,盗版必究。【本文首发于唐霜的博客】层?有必要吗?”就像我们接触毒药一样,离本文版权归作者所有,未经授权不得转载。【转载请注明来源】开了剂量谈毒是没有意义的,同样的道理,离【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net开了具体的业务复杂度谈分层,也是没有意义【本文受版权保护】【关注微信公众号:wwwtangshuangnet】的。在极为简单的应用中,我们当然要追求快【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net速高效立马上线,但在一些企业应用中,却需【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。要我们慢条斯理,在长达数年的岁月里慢慢推转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】进一套系统的演进。我们谈分层,大多是在这原创内容,盗版必究。【本文受版权保护】类有比较复杂的业务逻辑的系统中去谈,这类【版权所有,侵权必究】【本文受版权保护】系统可能在具体界面的呈现上实现起来并不复转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net杂,甚至没有什么交互上的难度。但是,这类本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。系统中的前端开发者们,常常还是很抓狂,因【原创内容,转载请注明出处】未经授权,禁止复制转载。为一个逻辑可能被折腾死,最后一定会思考,我们如何才能合理的区分哪些代码是业务的,【本文首发于唐霜的博客】【原创内容,转载请注明出处】哪些代码是交互的,应该如何组织代码才能高【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net效的解决自己遇到的烦恼?
【未经授权禁止转载】【作者:唐霜】【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。【本文首发于唐霜的博客】本文将阐述我在工作中的思考与解决的方案。【原创内容,转载请注明出处】【本文受版权保护】相信它可以帮助那些与我曾经一样遇到此类烦本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】恼的小伙伴。
转载请注明出处:www.tangshuang.net【作者:唐霜】本文作者:唐霜,转载请注明出处。烦恼从而而来?原创内容,盗版必究。
【版权所有,侵权必究】【作者:唐霜】【原创不易,请尊重版权】我们前端在开发一个业务的时候,总是先从界【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】面出发,看着界面想我这里要怎么做怎么做,【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。等把界面交互大致写出来之后,再把产品文档【关注微信公众号:wwwtangshuangnet】【作者:唐霜】里面的业务逻辑作为一些判断条件加入到写好【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。的交互代码中,最终交付。我能这么讲出来,本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。说明这里面有很大的问题。问题在哪里呢?我【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】们用一段假代码来看看:
转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。export default {
template: `
<form @submit="handleSubmit">
<input type="number" v-model="price" placeholder="单价" />
<input type="number" v-model="count" placeholder="数量" />
<input type="number" :value="total" disabled />
<span v-if="save">折扣10%</span>
<span>
<input type="text" v-model="code" @change="handleChangeCode" placeholder="优惠码" />
<button type="button">查询</button>
<span v-if="codeChecked">优惠码有效</span>
</span>
<button>提交</button>
</form>
`,
data() {
return {
price: 0,
count: 0,
code: '',
codeChecked: false,
}
},
computed: {
total() {
return this.price * this.count * (1 - this.save) * (this.codeChecked ? 0.9 : 1)
},
save() {
return this.price * this.count > 100 ? 10 : 0
},
},
methods: {
handleCheckCode() {
ajax.post('...', this.code).then(res => {
this.codeChecked = !!res
})
},
handleChangeCode() {
this.codeChecked = false
},
handleSubmit(e) {
e.preventDefault()
// ....
// 一大堆校验逻辑
const { price, count, code, codeChecked } = this
const data = { price, count }
if (codeChecked) {
data.code = code
}
// 提交数据
// 。。。
},
},
}
你看,也就简简单单几个字段,就让代码开始未经授权,禁止复制转载。【访问 www.tangshuang.net 获取更多精彩内容】有点点混乱了,要搞清楚每一个字段与其他字未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。段之间的关联,你需要通读整个组件的代码,【转载请注明来源】本文版权归作者所有,未经授权不得转载。而随着业务的越来越积累,这个看似简单的组本文作者:唐霜,转载请注明出处。【本文首发于唐霜的博客】件,会慢慢撑开,字段从这几个慢慢撑到10本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net多个,甚至20、30多个,字段与字段之间【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。的关联性,以及每一个字段和它的提示语在什原创内容,盗版必究。【未经授权禁止转载】么情况下才展示出来,等等,越来越复杂。当著作权归作者所有,禁止商业用途转载。【作者:唐霜】这个业务持续增长超过1年后,你发现这个组著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。件已经满目全非,根本不敢改一行代码,因为转载请注明出处:www.tangshuang.net【转载请注明来源】你怕一改就影响整个业务。
【本文受版权保护】【关注微信公众号:wwwtangshuangnet】【本文受版权保护】【原创内容,转载请注明出处】本文作者:唐霜,转载请注明出处。为什么呢?是什么东西,冥冥中让我们的代码【未经授权禁止转载】【版权所有,侵权必究】走向不可维护呢?
本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net我认为,一个重要原因在于:本文作者:唐霜,转载请注明出处。我们的代码同时承载了业务的逻辑和界面的交【本文受版权保护】未经授权,禁止复制转载。互逻辑。比如上面的codeChecked对于整个【作者:唐霜】著作权归作者所有,禁止商业用途转载。业务而言,是非必需的,但是对于交互而言是【转载请注明来源】【访问 www.tangshuang.net 获取更多精彩内容】必须的,你必须用一个状态去控制提示语是不本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。是要展示出来。因此,上面这段代码中,用于【版权所有,侵权必究】未经授权,禁止复制转载。完成业务目标的price, count,【版权所有,侵权必究】未经授权,禁止复制转载。 code,和用于完成交互任务的code【未经授权禁止转载】本文作者:唐霜,转载请注明出处。Checked被放在一起管理。而且更糟糕【转载请注明来源】【版权所有】唐霜 www.tangshuang.net的是,其中在handleSubmit中,未经授权,禁止复制转载。原创内容,盗版必究。用于交互的codeChecked却成为了【版权所有】唐霜 www.tangshuang.net【版权所有,侵权必究】控制code字段是否提交的开关,这直接让转载请注明出处:www.tangshuang.net【转载请注明来源】业务逻辑和交互逻辑耦合在一起,在未来的开转载请注明出处:www.tangshuang.net【关注微信公众号:wwwtangshuangnet】发中,你不可能把这两部分解耦开,因为这个【本文受版权保护】原创内容,盗版必究。逻辑写死了。
未经授权,禁止复制转载。【原创不易,请尊重版权】【原创内容,转载请注明出处】正因为这种线性的开发思维,让我们写的组件未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。随着业务的扩展,越来越难以高效的维护,直【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。到最后不敢修改一行。我称这种情况为“缠线本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。定律”,即一根线在比较短的时候不会打结,【版权所有,侵权必究】【访问 www.tangshuang.net 获取更多精彩内容】到一定长度后容易打结,当很长的时候一定会【原创不易,请尊重版权】【本文首发于唐霜的博客】打结,所以无论你的耳机线材质多有韧性,只本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。要直接塞在裤兜里,一定会打结。那么怎么避【转载请注明来源】【本文首发于唐霜的博客】免呢?就像避免耳机线打结一样,我们需要用未经授权,禁止复制转载。未经授权,禁止复制转载。一个耳机线盒把规整的线圈管理起来,有了盒【未经授权禁止转载】【原创内容,转载请注明出处】子的约束和隔离,耳机线打结的几率微乎其微【版权所有】唐霜 www.tangshuang.net【本文受版权保护】。同样的道理,我们需要对我们的代码重新进原创内容,盗版必究。【转载请注明来源】行管理,让原本线性的逻辑表达,按照一定的未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】结构重新梳理,并把这些结构用合理的文件结【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net构进行框定,从而做到不打结。
本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。【作者:唐霜】未经授权,禁止复制转载。【原创内容,转载请注明出处】领域模型【关注微信公众号:wwwtangshuangnet】
原创内容,盗版必究。原创内容,盗版必究。【原创内容,转载请注明出处】【访问 www.tangshuang.net 获取更多精彩内容】解决代码逻辑打结的第一个杀手锏是领域建模转载请注明出处:www.tangshuang.net【原创内容,转载请注明出处】。领域建模是指,我们先抛开软件的界面、实【原创不易,请尊重版权】【本文受版权保护】现逻辑、运行环境等应用层面的东西,转换自著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】己的角色,把自己当作一个业务人员,问自己【原创不易,请尊重版权】【访问 www.tangshuang.net 获取更多精彩内容】我用这套系统要完成什么业务目的,梳理出业【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net务流程,指明不同角色在业务流程中的责任,【关注微信公众号:wwwtangshuangnet】【本文首发于唐霜的博客】画出业务的示意图,并最终用代码把它表达出未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。来。
【访问 www.tangshuang.net 获取更多精彩内容】【转载请注明来源】【未经授权禁止转载】【本文首发于唐霜的博客】我们以往的做法是直接写代码,然后去和需求【本文首发于唐霜的博客】转载请注明出处:www.tangshuang.net方沟通,边沟通边改。但是我们经常遇到这样未经授权,禁止复制转载。【原创不易,请尊重版权】的情况,在一个天朗气清的工作日,我们开心【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】的去和业务方沟通下一步业务,结果业务方突本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。然冒出一句听上去自然而然的但却和你之前写【版权所有】唐霜 www.tangshuang.net【版权所有】唐霜 www.tangshuang.net的代码不一致的地方,这个时候,你一定会大著作权归作者所有,禁止商业用途转载。【版权所有】唐霜 www.tangshuang.net喊一声“稍等一下,刚才那个地方……”然后【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net是两个小时的重新确认和5个小时的重新编码【版权所有】唐霜 www.tangshuang.net【版权所有,侵权必究】!这样的场景在我有限的工作经历中,也经历【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】了不少次。
【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】解决这一问题的有效办法,是DDD提供的沟原创内容,盗版必究。【原创内容,转载请注明出处】通方法论,在开始编码之前,建立领域模型。【版权所有】唐霜 www.tangshuang.net【原创内容,转载请注明出处】实际上,领域模型包含两个部分,一部分叫统本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】一语言,说的直白些,就是图纸,在你的业务【转载请注明来源】本文版权归作者所有,未经授权不得转载。部门里任何人都能看的懂,另一部分是与图纸【关注微信公众号:wwwtangshuangnet】【转载请注明来源】等效的建模代码,在未来的日子里,任何的沟【本文首发于唐霜的博客】【转载请注明来源】通,大家只会基于图纸来明确某个细节,而不本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。会关心你写的代码,如果你的实现与图纸不一本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。致,那明显是你的问题,而不是图纸。
【转载请注明来源】本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。好了,接下来我们来聊一聊怎么做出个图纸等【未经授权禁止转载】本文作者:唐霜,转载请注明出处。价的建模代码。
未经授权,禁止复制转载。【原创内容,转载请注明出处】【访问 www.tangshuang.net 获取更多精彩内容】我们要清楚在这个过程中,其实主要包含3类【原创不易,请尊重版权】【本文受版权保护】对象,一类是描述业务的实体对象,是业务所【访问 www.tangshuang.net 获取更多精彩内容】【转载请注明来源】围绕的核心概念,你的公司所做的业务,本质【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】上就是在创建和处理这些对象。一类是描述工【访问 www.tangshuang.net 获取更多精彩内容】著作权归作者所有,禁止商业用途转载。作流程的服务对象,它们主要是对实体对象的【版权所有】唐霜 www.tangshuang.net【原创不易,请尊重版权】处理过程、逻辑、事件,是使得业务产生实际转载请注明出处:www.tangshuang.net【转载请注明来源】效果的非实体对象。最后一类是用于辅助完成【版权所有】唐霜 www.tangshuang.net【原创不易,请尊重版权】编程任务的程序对象,用以解决在特定编程语原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】言下面,怎么让你的业务的部分能够反馈到计【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.net算机系统中,用计算机系统的方式运行起来。【关注微信公众号:wwwtangshuangnet】著作权归作者所有,禁止商业用途转载。我们进行领域建模,主要针对第一类和第二类【原创不易,请尊重版权】原创内容,盗版必究。。
本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】面向对象是DDD的核心方法,我们在具体编【版权所有,侵权必究】【原创不易,请尊重版权】程时,通过创建和关联各种class完成模【原创内容,转载请注明出处】【版权所有,侵权必究】型。贫血和充血之争一直是一个问题,我认为原创内容,盗版必究。转载请注明出处:www.tangshuang.net在前端语境下,模型一定是充血的,因为前端【原创内容,转载请注明出处】【本文首发于唐霜的博客】建模要为交互留足空间。
【原创不易,请尊重版权】【作者:唐霜】未经授权,禁止复制转载。以前文的例子为例,我们可以建立这样的模型
本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。clas Order {
price = 0
count = 0
code = ''
total = 0
}
这种就是所谓的贫血模型,它只能告诉你有什未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net么,但是具体的业务你需要另外封装出来,这未经授权,禁止复制转载。【原创内容,转载请注明出处】显然不可能在前端领域成为合理的建模方式。转载请注明出处:www.tangshuang.net【版权所有,侵权必究】怎么做呢?我们要对每一个字段进行业务说明【版权所有】唐霜 www.tangshuang.net【原创不易,请尊重版权】,可以这样:
【未经授权禁止转载】本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。【本文首发于唐霜的博客】import { Model, meta, state, Int, Validator } from 'tyshemo'
class Order extends Model {
@meta({
type: Number,
label: '单价',
required: true,
validators: [
Validator.required('单价必填'),
],
})
price = 0
@meta({
type: Int,
label: '数量',
required: true,
validators: [
Validator.required('数量必填'),
],
})
count = 0
@meta({
type: String,
label: '优惠码',
checked: false,
checking: false
watch() {
const view = this.use('code')
view.checked = false
view.checking = true
ajax.post('...', this.code).then(res => {
view.checked = !!res
}).finally(() => {
view.checking = false
})
},
drop() {
return this.use('code').checked
},
validators: [
determine(code) {
return !!code && !this.use('code').checking = false
},
validate() {
return this.use('code').checked
},
message: '优惠码无效',
],
})
code = ''
@meta({
type: Number,
label: '总额',
compute() {
const { save } = this.use('total')
const { checked } = this.use('code')
return this.price * this.count * (1 - save) * (checked ? 0.9 : 1)
},
save() {
return this.price * this.count > 100 ? 10 : 0
},
saveMessage() {
return this.save ? '折扣10%' : ''
},
disabled: true,
drop: true, // 由后台计算,这个字段仅前端展示,不提交
})
total = 0
}
我们写完上面这个模型,它是充血的,它完整著作权归作者所有,禁止商业用途转载。【作者:唐霜】的描述了对应业务实体的所有字段,以及每个【转载请注明来源】【本文首发于唐霜的博客】字的的具体业务阐释。而且更重要的是,基于【原创不易,请尊重版权】转载请注明出处:www.tangshuang.net这一模型设计,我们可以从meta信息中,【原创内容,转载请注明出处】本文作者:唐霜,转载请注明出处。阅读每一个字段关于自己的全部逻辑。这种设未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。计的思路很清晰,就是字段本身的逻辑应该放原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】在字段的旁边,集合在一起,阅读关于字段本未经授权,禁止复制转载。原创内容,盗版必究。身的业务逻辑,只需要关注这一处代码,而不【原创内容,转载请注明出处】【原创不易,请尊重版权】需要跨多个上下文去理解。要了解一个字段的著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】全部逻辑,基本上可以在对应的meta中获【原创内容,转载请注明出处】【原创内容,转载请注明出处】得全部信息(必要的时候,需要阅读整个模型【作者:唐霜】【关注微信公众号:wwwtangshuangnet】的相关方法,找出多个字段有关联逻辑的业务【本文首发于唐霜的博客】【转载请注明来源】)。阅读这段代码,你不仅能理解代码本身【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。的意思,而且还能掌握业务的知识。
【本文首发于唐霜的博客】【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net你可能会想,我这些字段要怎么用。但是不要【版权所有,侵权必究】【版权所有,侵权必究】着急,到目前为止,我们只关心业务,不关心【访问 www.tangshuang.net 获取更多精彩内容】未经授权,禁止复制转载。界面和交互。
原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。领域服务【关注微信公众号:wwwtangshuangnet】
【原创内容,转载请注明出处】【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】转载请注明出处:www.tangshuang.net领域模型帮我们描绘了有关这个业务的核心对转载请注明出处:www.tangshuang.net【转载请注明来源】象的各种逻辑,但是,我们的这个业务实体会【关注微信公众号:wwwtangshuangnet】【关注微信公众号:wwwtangshuangnet】面对很多场景,每一个场景下,可能存在有些【作者:唐霜】本文版权归作者所有,未经授权不得转载。特定的转化逻辑,这就需要我们在领域模型的【本文首发于唐霜的博客】【原创内容,转载请注明出处】基础上,提供对应场景的服务。简单讲,你可【关注微信公众号:wwwtangshuangnet】【转载请注明来源】以把领域服务想象成领域模型实例的处理工厂【作者:唐霜】本文作者:唐霜,转载请注明出处。,在这些处理中,我们是为了描述特定场景下本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。的业务需求,所以,领域服务仍然是业务描述未经授权,禁止复制转载。未经授权,禁止复制转载。,和UI无关。
本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。【转载请注明来源】转载请注明出处:www.tangshuang.net一般而言,我们在不需要的时候,就不需要领本文作者:唐霜,转载请注明出处。【原创不易,请尊重版权】域服务。
本文版权归作者所有,未经授权不得转载。【转载请注明来源】【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net怎么讲?在领域模型的分类中,除了实体、【关注微信公众号:wwwtangshuangnet】【访问 www.tangshuang.net 获取更多精彩内容】值,还有一类叫“聚合”的模型,大部分情况本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。下,在聚合中我们就可以调动子模型完成各种本文版权归作者所有,未经授权不得转载。【未经授权禁止转载】处理,因此,如果通过聚合就可以完成不同场本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。景的业务处理需求,我们就不需要领域服务。转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net但是,假如实在没有办法,我们就应该考虑用本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。领域服务完成业务描述。
本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。【版权所有】唐霜 www.tangshuang.net以上面的例子为例,同样是订单,我们可能面【原创内容,转载请注明出处】未经授权,禁止复制转载。临创建和编辑两种业务场景。编辑的时候,和【版权所有】唐霜 www.tangshuang.net【关注微信公众号:wwwtangshuangnet】新建稍有不同,需要从服务端接口拉取数据,本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。并填充,而创建时则不需要。这也就意味着,【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。相同的领域模型,具有多态性。如何解决呢,著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net我们可在领域模型之上,提供领域服务,用以【未经授权禁止转载】【版权所有,侵权必究】在不同场景下进行调用。此处的处理方式有两【本文首发于唐霜的博客】未经授权,禁止复制转载。种,一种是直接对类进行扩展,编辑的时候,【转载请注明来源】【版权所有,侵权必究】使用扩展的类,比如:
【原创不易,请尊重版权】未经授权,禁止复制转载。【转载请注明来源】class OrderService {
static toEdit(Order) {
return class OrderEdit extends Order {
constructor() {
super()
ajax.get('...').then(data = this.fromJSON(data))
}
}
}
}
// 使用
OrderService.toEdit(Order)
另一种方式是直接在服务内对实例进行数据填未经授权,禁止复制转载。【原创不易,请尊重版权】塞。例如:
【作者:唐霜】【未经授权禁止转载】【原创内容,转载请注明出处】【原创内容,转载请注明出处】class OrderService {
static recoverOrder(order, order_id) {
ajax.get(`.../${id}`).then(data => order.fromJSON(data))
}
}
总而言之,领域模型是相对比较普遍的业务描【作者:唐霜】转载请注明出处:www.tangshuang.net述,而领域服务是相对比较特殊的业务描述。
原创内容,盗版必究。【原创内容,转载请注明出处】【原创内容,转载请注明出处】【本文首发于唐霜的博客】著作权归作者所有,禁止商业用途转载。另外,一般来讲,服务需要遵循无状态的原则【本文受版权保护】【版权所有】唐霜 www.tangshuang.net,状态一般会放在领域模型中。
未经授权,禁止复制转载。【原创不易,请尊重版权】著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net交互模型【未经授权禁止转载】
本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】【本文受版权保护】【原创内容,转载请注明出处】至此为止,我们的编码还没有涉及UI或交互【转载请注明来源】本文作者:唐霜,转载请注明出处。。这其实有悖以往的编程经验,“怎么界面都【作者:唐霜】【关注微信公众号:wwwtangshuangnet】还没有开始写就已经有一大堆代码了?”是的【原创内容,转载请注明出处】【未经授权禁止转载】,这是我们实现目标“把业务逻辑从交互代码【本文首发于唐霜的博客】【本文首发于唐霜的博客】中解救出来“的必经之路。我们要有一层专门著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。去完成业务逻辑,而领域层就是做业务逻辑的原创内容,盗版必究。未经授权,禁止复制转载。。领域层是静态的,描述性质的,因此,可以本文作者:唐霜,转载请注明出处。【原创不易,请尊重版权】承载业务知识体系。
转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。【未经授权禁止转载】有了核心的业务逻辑了,接下来,我们就要考【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。虑在应用中完成界面和交互,这和后端完全不【访问 www.tangshuang.net 获取更多精彩内容】【作者:唐霜】同,后端实施DDD,没有这一层,业务到D未经授权,禁止复制转载。【本文受版权保护】O就结束了,而前端则还要继续,完成人机交【未经授权禁止转载】本文版权归作者所有,未经授权不得转载。互的真实效果。所以,我在某些场合讲,前端本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。DDD比后端在某些方面更复杂(当然,后端转载请注明出处:www.tangshuang.net【本文受版权保护】也很复杂,需要考虑很多数据持久化相关的架本文作者:唐霜,转载请注明出处。【关注微信公众号:wwwtangshuangnet】构问题)。
转载请注明出处:www.tangshuang.net【原创不易,请尊重版权】【本文首发于唐霜的博客】而且,在我们的产品文档中,经常会这样描述【原创内容,转载请注明出处】【原创内容,转载请注明出处】:
【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。转载请注明出处:www.tangshuang.net【版权所有,侵权必究】【原创内容,转载请注明出处】原创内容,盗版必究。转载请注明出处:www.tangshuang.net【未经授权禁止转载】当用户点击“提交”按钮的时候,该订单被发【访问 www.tangshuang.net 获取更多精彩内容】【版权所有,侵权必究】送给检验员进行核对。
【原创不易,请尊重版权】【原创内容,转载请注明出处】【版权所有,侵权必究】【原创不易,请尊重版权】
很明显,产品经理在写这句话文档时,是在描【版权所有】唐霜 www.tangshuang.net【转载请注明来源】述一个业务过程。“点击提交按钮”这个动作【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】是交互层面的,它无法由后端完成,后端只能【原创内容,转载请注明出处】原创内容,盗版必究。完成这个动作之后的跟随动作,也就是“订单【转载请注明来源】【版权所有】唐霜 www.tangshuang.net被发送给检验员”。那么,“点击提交按钮”才能【原创不易,请尊重版权】触发“订单被发送给检验员”这个业务逻辑,转载请注明出处:www.tangshuang.net【未经授权禁止转载】你能说不是业务逻辑吗?这种事情往往有屁股本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net坐哪里哪里就是真理的意味,后端人员不管理未经授权,禁止复制转载。【原创内容,转载请注明出处】任何交互行为,因此,他们斩钉截铁的说“这【原创内容,转载请注明出处】未经授权,禁止复制转载。不是业务逻辑”,其实,他们想要表达的是“【本文首发于唐霜的博客】未经授权,禁止复制转载。这不是我们后端的原创内容,盗版必究。业务逻辑“。这就有点变味了,产品文档中的【本文受版权保护】【版权所有】唐霜 www.tangshuang.net一句话,只有一半是业务逻辑,你觉得说得通【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。吗?所以,我在很多场景下都讲,交互有两种,一种是界面交互,一种是业务交本文版权归作者所有,未经授权不得转载。著作权归作者所有,禁止商业用途转载。互。在这个例子中,“点击提交按钮”就是业务原创内容,盗版必究。【原创不易,请尊重版权】交互。
【本文首发于唐霜的博客】【未经授权禁止转载】【关注微信公众号:wwwtangshuangnet】【本文受版权保护】作为前端开发者,需要分清楚“界面”和“交本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。互”存在一定的区别。界面,交互,它们在某转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】些情况下是统一体,不可分割,但是在另外一本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。些情况下,却是独立的,或者说“业务交互”著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】是可以独立于界面存在的。
本文版权归作者所有,未经授权不得转载。【原创不易,请尊重版权】【本文受版权保护】以上面这个“点击提交按钮”为例。你知道这【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。个“点击”动作是一个click事件,但是本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】我想问的是,你现在知道这个按钮是以什么样【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net的界面展示的么?是红色的按钮,还是灰色的【版权所有】唐霜 www.tangshuang.net【转载请注明来源】?是方角的还是圆角的?是短的,还是长条的【未经授权禁止转载】原创内容,盗版必究。?是不是都不清楚?或许产品经理在写下这句【原创内容,转载请注明出处】【访问 www.tangshuang.net 获取更多精彩内容】话时,确实脑海中有一个界面的形状,但是在转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】业务本身的过程中,这里是没有界面的,它是【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。一句抽象描述,对于编码而言,就是一个抽象【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。的表达,因此,我说这里要建立交互模型原创内容,盗版必究。。【访问 www.tangshuang.net 获取更多精彩内容】
未经授权,禁止复制转载。原创内容,盗版必究。【本文受版权保护】原创内容,盗版必究。【转载请注明来源】什么是交互模型?【版权所有,侵权必究】
【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】【原创内容,转载请注明出处】就是在没有界面的情况下,对产品文档中的业【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。务交互进行的建模。一般情况下,交互模型会未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。引用领域模型和领域服务,同时,它还会被用【转载请注明来源】【未经授权禁止转载】到视图层中,交给视图层使用。说白了,站在【转载请注明来源】原创内容,盗版必究。视图层编程的角度讲,你可以把交互模型和我著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net们平时讲的“状态管理器”划一个约等号,交【未经授权禁止转载】本文作者:唐霜,转载请注明出处。互模型的实例向视图层提供状态属性和方法,未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。属性用于视图层进行渲染,而方法用于事件回本文作者:唐霜,转载请注明出处。【转载请注明来源】调。
未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。【转载请注明来源】【本文首发于唐霜的博客】转载请注明出处:www.tangshuang.net在上面的例子中,我们创建这样的交互模型:
【关注微信公众号:wwwtangshuangnet】【原创不易,请尊重版权】【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。import { Controller } from 'nautil'
class OrderEditController {
static model = Order
// 需要在视图层赋值
onError = null
recover(order_id) {
OrderService.toEdit(this.model, order_id)
}
async submit() {
const errors = this.model.validate()
if (errors.length) {
this.onError?.(errors.message)
return
}
const data = this.model.toData()
const res = await ajax.post('xxx', data) // 这个接口可能就是我们上面说的发送给检验员
return res
}
}
这样,我们就创建好了一个交互模型。你看它【本文受版权保护】【原创内容,转载请注明出处】的表达是否很清晰呢?而此时,你有没有发现【未经授权禁止转载】【未经授权禁止转载】,到现在为止,你还没有写任何的视图层面的【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net代码。到目前为止,我们已经把需求文档中,【关注微信公众号:wwwtangshuangnet】【本文受版权保护】有关业务的部分完全表达出来了,用领域模型【版权所有】唐霜 www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】和领域服务表达了业务实体及对应的处理逻辑【转载请注明来源】【转载请注明来源】,用交互模型表达了某些业务交互。是不是很【本文首发于唐霜的博客】【未经授权禁止转载】神奇,在没有开始写界面的时候,我们就已经【本文受版权保护】【版权所有】唐霜 www.tangshuang.net完成了大部分逻辑的编写。
【转载请注明来源】著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。等一等,在进入下一个部分之前,我还要在补【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。充一点。
【未经授权禁止转载】著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。假如你的业务系统有PC端和APP端,其中【原创内容,转载请注明出处】著作权归作者所有,禁止商业用途转载。PC端是基于react的,APP端是基于【原创不易,请尊重版权】转载请注明出处:www.tangshuang.netreact native的,到目前为止,著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。你有没有发现,由于我们上述代码中没有任何【访问 www.tangshuang.net 获取更多精彩内容】【本文首发于唐霜的博客】视图层的编码,所以,我们上述的代码全部都原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。是可以在两端复用的,但是由于react和【转载请注明来源】未经授权,禁止复制转载。react native视图层编程方式不【版权所有】唐霜 www.tangshuang.net【转载请注明来源】同,而且,设计稿也会不一样,PC和APP原创内容,盗版必究。原创内容,盗版必究。的设计稿几乎不可能一样,所以,视图层的代【关注微信公众号:wwwtangshuangnet】【转载请注明来源】码,我们必须一定肯定是会有两份的(当然,本文版权归作者所有,未经授权不得转载。【作者:唐霜】还有一种多端同构的方案,你可以了解一下我【原创内容,转载请注明出处】【原创内容,转载请注明出处】写的框架 nautil https://github.com/t【本文受版权保护】本文版权归作者所有,未经授权不得转载。angshuang/nautil )。现在,业务交互逻辑都已经完成了,两【作者:唐霜】【版权所有】唐霜 www.tangshuang.net端虽然需要写自己的视图层代码,但是,这些著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】与业务相关的逻辑,却不需要再重新编写了,【原创内容,转载请注明出处】本文作者:唐霜,转载请注明出处。可以拿过来就用。你可以把两端的代码放在一【转载请注明来源】【本文受版权保护】个git仓库中,这样,就可以直接共用一份未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。业务代码。
本文版权归作者所有,未经授权不得转载。【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】另外,前端的单元测试是很难做的,因为UI本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。测试非常麻烦,虽然也能做,但是效率并不高原创内容,盗版必究。【作者:唐霜】。而将业务的领域模型和交互模型独立出来之【版权所有】唐霜 www.tangshuang.net【原创不易,请尊重版权】后,你可以发现,虽然我做不了UI测试,但本文作者:唐霜,转载请注明出处。【本文首发于唐霜的博客】是我可以做业务逻辑的测试,这样,我可以保本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。证我的业务逻辑是准确的,在持续的维护中,【作者:唐霜】【原创内容,转载请注明出处】有测试用例做保障,任何人的改动所带来的破【版权所有】唐霜 www.tangshuang.net【作者:唐霜】坏,都是不允许的,这就保证我们的业务层面【访问 www.tangshuang.net 获取更多精彩内容】【版权所有,侵权必究】的逻辑是OK的。
未经授权,禁止复制转载。【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net薄薄的视图层【本文受版权保护】
【版权所有,侵权必究】著作权归作者所有,禁止商业用途转载。【作者:唐霜】著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。有人多次给我评论讲,前端就应该是胖UI。未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。对于这一点我不置可否,不过在我看来,胖U【转载请注明来源】未经授权,禁止复制转载。I的前提是在剖离业务逻辑,纯界面交互的情【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】况下讲胖UI才是准确的。以react为例著作权归作者所有,禁止商业用途转载。【版权所有,侵权必究】,我们的一个react应用中有组件,有状本文作者:唐霜,转载请注明出处。本文版权归作者所有,未经授权不得转载。态管理,有路由管理,这些都是应该的,但问【版权所有,侵权必究】本文版权归作者所有,未经授权不得转载。题在于,是因为基于react的视图层处理【转载请注明来源】【转载请注明来源】导致我们的代码臃肿了,还是因为我们一边写【版权所有,侵权必究】【版权所有,侵权必究】界面交互一边处理业务逻辑把代码撑肥了呢?
【原创不易,请尊重版权】【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net原创内容,盗版必究。回到我们文首的例子中,在我们有了建模成果【版权所有,侵权必究】转载请注明出处:www.tangshuang.net后,我们可以写界面了:
【未经授权禁止转载】【访问 www.tangshuang.net 获取更多精彩内容】原创内容,盗版必究。未经授权,禁止复制转载。import { Component } from 'nautil'
import { Form, FormItem } from 'react-tyshemo-form'
import { Toast } from '...some toast library...'
class OrderForm extends Component {
constructor(props) {
this.controller = new OrderController()
this.controller.onError = Toast.error
}
onInit() {
const { id } = this.props
this.controller.recover(id)
}
async handleSubmit = (e) => {
e.preventDefault()
const res = await this.controller.submit()
const { ... } = res
// ... 做一些跳转之类的
}
render() {
return (
<Form model={this.controller.model} onSubmit={}>
<FormItem name="price" component={['input', { type: 'number' }]} />
<FormItem name="count" component={['input', { type: 'number' }]} />
<FormItem name="code" component="input" />
<FormItem name="total" render={({ value, onChange, saveMessage }) => {
return (
<span>
<input value={value} onChange={onChange} />
{saveMessage ? <span>{svaeMessage}</span> : null}
</span>
)
}} />
<button>提交</button>
</Form>
)
}
}
现在,你可以发现,我们在视图层,主要是对【原创不易,请尊重版权】本文作者:唐霜,转载请注明出处。已经写好的controller进行操作和未经授权,禁止复制转载。【版权所有】唐霜 www.tangshuang.net使用,在视图层的所有代码,基本上都是和界转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。面与界面交互相关的,而几乎没有看到任何业原创内容,盗版必究。【原创不易,请尊重版权】务的影子。
【原创内容,转载请注明出处】【转载请注明来源】本文作者:唐霜,转载请注明出处。我们基于类似的思路,可以把写好的领域模型原创内容,盗版必究。【转载请注明来源】、交互模型再次用到react nativ未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。e,甚至跨一个框架,用到vue中去,因为本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。它们本身和框架无关,所以你在任何框架中都【版权所有,侵权必究】【本文受版权保护】可以使用它们。
本文版权归作者所有,未经授权不得转载。【转载请注明来源】【版权所有,侵权必究】然而,这里会有一个问题,不同的框架要使用【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net这些代码,还存在一个和框架进行结合的东西未经授权,禁止复制转载。未经授权,禁止复制转载。,比如vue的响应式系统是基于Objec【版权所有】唐霜 www.tangshuang.net【转载请注明来源】t.defineProperty或Pro【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.netxy的,react是基于内部的fiber【原创内容,转载请注明出处】【作者:唐霜】的,angualr是基于脏检查的,这就导著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net致不同的框架里面,你想要使用同一套代码的【本文首发于唐霜的博客】原创内容,盗版必究。话,你就需要有一个把建模代码和框架的响应转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。式系统连接起来的东西,比如上面我用到了r【作者:唐霜】【原创内容,转载请注明出处】eact-tyshemo-form,它就转载请注明出处:www.tangshuang.net【访问 www.tangshuang.net 获取更多精彩内容】是一个连接工具。此外,比较优雅的工具有M【关注微信公众号:wwwtangshuangnet】【转载请注明来源】obx,你可以了解一下这个工具,利用Mo【未经授权禁止转载】【原创内容,转载请注明出处】bx来写controller,将非常有利【转载请注明来源】【版权所有】唐霜 www.tangshuang.net于在vue或react中使用相同一个cl【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。ass,因为它提供了覆盖全框架的连接工具本文版权归作者所有,未经授权不得转载。本文版权归作者所有,未经授权不得转载。。
【转载请注明来源】【访问 www.tangshuang.net 获取更多精彩内容】本文作者:唐霜,转载请注明出处。结语【作者:唐霜】
【原创不易,请尊重版权】【原创内容,转载请注明出处】本文版权归作者所有,未经授权不得转载。在前端这样去思考和实践,是和我们以往的一【转载请注明来源】【关注微信公众号:wwwtangshuangnet】些习惯不符的,这需要我们慢慢体会。现在,本文作者:唐霜,转载请注明出处。【未经授权禁止转载】我并不需要你立即接受这种开发思维,但是你【版权所有,侵权必究】未经授权,禁止复制转载。可以先了解它,直到有一天,你突然发现,你著作权归作者所有,禁止商业用途转载。未经授权,禁止复制转载。的业务系统开始在庞大的组件网络中变得难以【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net维护时,可以再找出这篇文章,阅读一下,获【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】得一些思路,然后重新梳理你的代码组织。
【版权所有】唐霜 www.tangshuang.net【本文受版权保护】原创内容,盗版必究。未经授权,禁止复制转载。这样的代码组织还面临一个问题,我想你也会原创内容,盗版必究。本文作者:唐霜,转载请注明出处。思考到这个问题,就是:模型、控制器、视图转载请注明出处:www.tangshuang.net原创内容,盗版必究。,应该放在不同的目录中,还是放在同一个目著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。录中?我认为这个问题还是需要根据实际的情著作权归作者所有,禁止商业用途转载。【本文受版权保护】况来看。但是,就我个人而言,更倾向于将一著作权归作者所有,禁止商业用途转载。【作者:唐霜】个模块的模型、控制器、视图放在一个模块目【原创内容,转载请注明出处】未经授权,禁止复制转载。录中,这个模块从某些意义上,可以从这个项【原创不易,请尊重版权】转载请注明出处:www.tangshuang.net目拖到另外一个需要这个模块的项目中去,你【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】只需要在顶层的应用上,组织和使用这个业务【版权所有,侵权必究】【版权所有】唐霜 www.tangshuang.net模块。但是,在一些情况下,比如你有多端同【版权所有,侵权必究】【原创不易,请尊重版权】时一起开发,那么就要好好考虑,在实践中摸【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.net索,到底应该怎么组织代码目录。
著作权归作者所有,禁止商业用途转载。【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。
最后,如果你在平日的业务代码开发中,也遇原创内容,盗版必究。转载请注明出处:www.tangshuang.net到类似的问题和烦恼,或者你认为本文中的某【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net些看法,还有改进之处,可以在本文或知乎专【未经授权禁止转载】未经授权,禁止复制转载。栏“前端数据治理之道”下方留言一起探讨。
【原创内容,转载请注明出处】未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。


最近在实际业务中遇到了类似的问题,也在思考如何通过将业务和交互分离。看完这篇文章有些感触,总感觉现在自己对于业务交互进行拆分划分时总有些朦胧不清的东西在阻碍着,无从下手的感觉。希望作者可以针对一些简单实际业务场景进行实战演练,这样结合文章中的思想可能感受更深刻。感谢作者的分享!
感谢你的关注。
很多人向我提出过类似的需求,也是希望有实际的代码来聊一聊这个事情。
但是能够公开演示的代码并不多,毕竟任何开源的项目,都不是以某个业务为目标的。
文章的这些想法理念,都需要在工作中去思考、尝试和实践。
如果有任何的朋友看到这条评论,并且愿意拿出自己的业务代码来一起讨论,不妨加我微信,我们可以一起通过代码来展开讨论。
随着工作时间的增加,也有了烦恼对于逻辑与业务耦合的烦恼,对于入行两年的我可以学到很多东西。谢谢大佬。
我把 “指标”划分为model,不同类型的“报表”划分为不同modules,报表中都会使用到指标,这样的话是否就不适合把model放到modules目录下,而要让model目录和modules目录同级,使用会更加灵活
“划分”要整体的看系统的看,单纯从某一点讲,都是有道理的,但是当下一次遇到某些情况的时候,又觉得放在另外一个地方更合适,我建议是先把整个系统的架构分层理清楚,再去斟酌领域代码的管理以及具体业务层面代码的管理
写的很好,看了你之前的一批关于React的DDD架构,理念和我一直以来的思维模式不能说相似,只能说一模一样。前端绝对有必要对业务代码进行充分的抽象建模。而当前的大多数项目都是之间采用的Vue Cli和React cli模板,这些并称不上架构,只不过是实现了一个前端行业的标准化代码结构而以。
关于领域模型的设计,控制器,UI视图的分层理念,简直是知音。最近这一个月都在翻google上的一些文章,没想到在百度上能搜到这么一篇!
对我而言,稳定、支撑了我的理念,帮助很大!
感谢支持,可以加微信一起探讨
在vue中如何具体的实现,如果要写一个CRUD的页面的话
关注我博客或b站,后续会有内容专门以案例来讲
期待ing…
其实,他们想要表单的是“这不是我们后端的业务逻辑“ . 表达写成了表单。
已更新,感谢指出
如果原来的项目大量依赖hooks, 业务逻辑与页面耦合的很死.这时该如何进行分层呢? 难道需要重构所有hooks吗?
使用hooks是属于视图层的处理,所以使用hooks和不使用hooks都是一样的,都是在视图层中写业务逻辑,并没有做到任何分层的设计。
如果确定要重构,应该将这些业务逻辑独立出来,层层抽象,这跟是否使用hooks没有任何关系。
豁然开朗, 要重构的话,也不是重构hooks, 而是把hooks再反向抽象成业务逻辑. 看来重构不太现实了
像 handleSubmit 时的loading状态会存在哪一层呢, 在视图层上吗?
loading在控制器里面可以有,在视图层也可以有,在控制器里面是用于控制某些动作的状态,在视图层用于控制显示界面。当然,你可以直接把控制器的loading暴露出来给视图层用,这样就只有一个loading。而且,就这个场景,可以考虑一下,在控制器里面引入xstate这类状态机工具,解决复杂的状态流转问题。
原来如此,两个地方的loading虽然含义不同但是也能通用.
状态机工具我没了解过,不过涉及到复杂的异步校验的时候,确实会需要借助工具来管理.
文中的例子里页面的跳转是写在视图层里的, 但有些时候, submit后的跳转页面也会跟业务有关. 按这样理解的话, 这时的跳转就会被写在控制器里,在视图层调用跳转方法吧.
是的,你可以把控制器理解为与UI无关的模型