时间:2023-06-02 08:12:02 | 来源:网站运营
时间:2023-06-02 08:12:02 来源:网站运营
WEB的三种设计模式:前端作为软件工程长期发展出来的一个独立分支,一直没有属于自己的特定的代码设计模式,最近我们在实践中对一些发源于面向对象的代码设计做了一些总结。const Table = createComponent({ name:'table', state:{ data:[], }, view:{ render(){ return( <div>{this.state.data.map(d=>{ return d })}<div> ) } }})const Page = createComponent({ name:'page', view:{ render(){ return( <Table /> ) } }})复制代码
这种模式我们都很熟悉,Page 和 Table 是两个拥有独立上下文的组件,在不同的 UI 框架里有不同的组件交互方式,在 React 中,Page 如果要和 Table 进行交互,可以使用 props 传递,或者借助 Context 来共享一部分上下文。const HeadTitle = ({text})=>{ return( <p>{text}</p> )}const Page = createComponent({ name:'page', state:{ text:'page', }, view:{ render(){ <HeadTtile text={this.state.text}> } }})复制代码
在这个示例中,乍看是没啥问题,平时我们都会将一些无状态的 UI 提取为无状态的函数组件,但经过实践你会发现实际上,HeadTitle 大概率仅服务于 Page,也就是说 HeadTitle 并不是为了复用而被提取,更多是因为大型组件的文件需要拆解从而减小体积,降低管理难度。function print(name){ console.log(name)}function main(){ const name = 'main' print(name)}// 如果 print 在 main 函数内部则不需要再次传递 namefunction main(){ const name = 'main' function print(){ console.log(name) } print(name)}// 因此对于 main 来说 print 是一个独立函数?,还是一个代码片段?复制代码
为了解决组件提取导致的上下文隔离问题,我们实践了一种模式,我们称之为组合模式const table = createCompose({ view:{ renderTable(){ return( <div>{this.state.data.map(d=>{ return d })}<div> ) } }})const head = createCompose({ state:{ text:'page' }, view:{ renderHead(){ return( <p>{text}</p> ) } }})const Page = createComponent(compose({ name:'page', state:{ data:[] }, view:{ render(){ <> {this.view.renderHead()} {this.view.renderTable()} </> } }},[table, head]))复制代码
现在 head 和 table 都成了组合体,通过组合变成了 page 的一部分,为此他们可以共享彼此的上下文,而不用额外通过 props 或者 Context 来传递或者共享参数const pageTemplate = () => { return { state:{ name:'', }, service:{ init(){} }, controller:{ onMount(){ this.service.init() } }, view:{ render(){ return( <div>{this.state.name}</div> ) } } }}const Page1Membrane = createMembrane(pageTemplate(), { name:'page-1-membrane', service:{ init(){ this.setter.name('page-1-membrane') } }})const Page1Membrane = createMembrane(pageTemplate(), { name:'page-1-membrane', service:{ init(){ this.setter.name('page-2-membrane') } }})const Page1 = createComponent(Page1Membrane)// render Page1 name === page-1-membraneconst Page2 = createComponent(Page2Membrane)// render Page2 name === page-2-membrane复制代码
如果你熟悉面向对象设计,那么可能会很快联想到 membrane 和 抽象类的特性有些相似,不过相比抽象类,membrane 可以包含具体的实现,因此两者也不完全等价,但是从设计上是有一定的共通性的关键词:设计,模式