百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

前端代码的三种设计模式(前端代码的三种设计模式是什么)

sinye56 2024-10-22 16:25 7 浏览 0 评论

组件模式

组件模式是我们用的最多的或者说目前大家都唯一能够理解的模式,组件模式的特点是,予以每个组件独立的上下文,组件和组件之间有严格的代码隔离,通常在不考虑全局变量的影响下组件之间是完全无潜在交互的。


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 函数内部则不需要再次传递 name
function main(){
  const name = 'main'
  function print(){
    console.log(name)
  }
  print(name)
}
// 因此对于 main 来说 print 是一个独立函数?,还是一个代码片段?
复制代码

为了解决组件提取导致的上下文隔离问题,我们实践了一种模式,我们称之为组合模式

组合模式

和组件模式相比,组合模式是一种轻量化的方案,相比组件模式两者有明显的区别

  1. 组件模式拥有独立的上下文,组件和组件之间组合成新的组件需要进行上下文的传递,而组合模式则只是组件的一个片段,若干个组合体组成了一个完整组件,组合体之间共享上下文,不需要额外传递,但组合体本身实现了相关逻辑的内聚
  2. 组件和组件之间因为上下文隔离,因此可以拥有相同的内部成员,组合体只是组件的一个片段,组合体之间不能用相同的内部成员。
  3. 组件有实例,需要命名标识,组合体没有实例,不需要命名标识

参照以上区别我们来看看的代码示例

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 来传递或者共享参数

除了组合模式,我们还总结了第三种模式,membrane 模式,这种模式我在早期的文章中有提到过,今天我们将其简化。

Membrane 模式

和组合模式相比,membrane 模式具有一些共通性,例如同样没有独立的上下文,不需要命名标识,不过两者也有极大的区别

  1. membrane 是一种抽象模式,和组合模式相比,每个 membrane 只能有一个模板
  2. compose 和 membrane 可以联合使用
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-membrane

const Page2 = createComponent(Page2Membrane)
// render Page2 name === page-2-membrane

复制代码

如果你熟悉面向对象设计,那么可能会很快联想到 membrane 和 抽象类的特性有些相似,不过相比抽象类,membrane 可以包含具体的实现,因此两者也不完全等价,但是从设计上是有一定的共通性的

在实际实践中,我们结合上述三种模式,借助类似 mermaid 这样的 UML 图形库,在日常迭代中增加了前端设计相关的内容,从实际结果看我们认为这些模式有助于改善前端设计的粗糙和非专业性,同时可以改善前端代码的标准化程度,利用 UML 图更好的代替注释和文字文档来描述业务代码的组成关系

相关推荐

程序员:JDK的安装与配置(完整版)_jdk的安装方法

对于Java程序员来说,jdk是必不陌生的一个词。但怎么安装配置jdk,对新手来说确实头疼的一件事情。我这里以jdk10为例,详细的说明讲解了jdk的安装和配置,如果有不明白的小伙伴可以评论区留言哦下...

Linux中安装jdk并配置环境变量_linux jdk安装教程及环境变量配置

一、通过连接工具登录到Linux(我这里使用的Centos7.6版本)服务器连接工具有很多我就不一一介绍了今天使用比较常用的XShell工具登录成功如下:二、上传jdk安装包到Linux服务器jdk...

麒麟系统安装JAVA JDK教程_麒麟系统配置jdk

检查检查系统是否自带java在麒麟系统桌面空白处,右键“在终端打开”,打开shell对话框输入:java–version查看是否自带java及版本如图所示,系统自带OpenJDK,要先卸载自带JDK...

学习笔记-Linux JDK - 安装&amp;配置

前提条件#检查是否存在JDKrpm-qa|grepjava#删除现存JDKyum-yremovejava*安装OracleJDK不分系统#进入安装文件目...

Linux新手入门系列:Linux下jdk安装配置

本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。注意:L...

测试员必备:Linux下安装JDK 1.8你必须知道的那些事

1.简介在Oracle收购Sun后,Java的一系列产品就被整合到Oracle官网中,打开官网乍眼一看也不知道去哪里下载,还得一个一个的摸索尝试,而且网上大多数都是一些Oracle收购Sun前,或者就...

Linux 下安装JDK17_linux 安装jdk1.8 yum

一、安装环境操作系统:JDK版本:17二、安装步骤第一步:下载安装包下载Linux环境下的jdk1.8,请去官网(https://www.oracle.com/java/technologies/do...

在Ubuntu系统中安装JDK 17并配置环境变量教程

在Ubuntu系统上安装JDK17并配置环境变量是Java开发环境搭建的重要步骤。JDK17是Oracle提供的长期支持版本,广泛用于开发Java应用程序。以下是详细的步骤,帮助你在Ubuntu系...

如何在 Linux 上安装 Java_linux安装java的步骤

在桌面上拥抱Java应用程序,然后在所有桌面上运行它们。--SethKenlon(作者)无论你运行的是哪种操作系统,通常都有几种安装应用程序的方法。有时你可能会在应用程序商店中找到一个应用程序...

Windows和Linux环境下的JDK安装教程

JavaDevelopmentKit(简称JDK),是Java开发的核心工具包,提供了Java应用程序的编译、运行和开发所需的各类工具和类库。它包括了JRE(JavaRuntimeEnviro...

linux安装jdk_linux安装jdk软连接

JDK是啥就不用多介绍了哈,外行的人也不会进来看我的博文。依然记得读大学那会,第一次实验课就是在机房安装jdk,编写HelloWorld程序。时光飞逝啊,一下过了十多年了,挣了不少钱,买了跑车,娶了富...

linux安装jdk,全局配置,不同用户不同jdk

jdk1.8安装包链接:https://pan.baidu.com/s/14qBrh6ZpLK04QS8ogCepwg提取码:09zs上传文件解压tar-zxvfjdk-8u152-linux-...

运维大神教你在linux下安装jdk8_linux安装jdk1.7

1.到官网下载适合自己机器的版本。楼主下载的是jdk-8u66-linux-i586.tar.gzhttp://www.oracle.com/technetwork/java/javase/downl...

window和linux安装JDK1.8_linux 安装jdk1.8.tar

Windows安装JDK1.8的步骤:步骤1:下载JDK打开浏览器,找到JDK下载页面https://d.injdk.cn/download/oraclejdk/8在页面中找到并点击“下载...

最全的linux下安装JavaJDK的教程(图文详解)不会安装你来打我?

默认已经有了linux服务器,且有root账号首先检查一下是否已经安装过java的jdk任意位置输入命令:whichjava像我这个已经安装过了,就会提示在哪个位置,你的肯定是找不到。一般我们在...

取消回复欢迎 发表评论: