这是我参与更文挑战的第12天,活动详情查看: 更文挑战
面向对象的概念
OOP: Object Oriented Programming 面向对象程序设计。这里的概念是从强类型语言开始。当然前端javascript随着时代的进步,也出现面向对象编程。面向对象编程里面有一些重要的概念。
- 对象
- 类
- 封装
- 聚合
- 重用与继承
- 多态
对象
对象,前端当中经常创建对象,然后就开始了往里面塞东西,个人理解:我们还只是在将对象作为数据结构的形式使用,并不是在做面向对象编程。当然这本身和前端的工作相关,前端的很多业务工作,是在获取后端返回的数据,进行一些数据逻辑处理,进行页面展示。用java举例,mvc的框架当中,前端承载的更多的是view层数据渲染。所以可能看着前端面向对象编程的使用场景不多。
后来随着,knockout,angular,react,vue的兴起。出现了mv** 框架。框架设计层次当中,是在使用面向对象编程设计。
oop的语义中,对象特征称之为属性,动作称之为方法。
- 对象往往是用名词表示
- 方法一般是动词
- 属性值是一些形容词
举例
The black cat sleeps on my head。
- the cat:对象名词
- black:颜色属性值
- sleep:动作方法
- on my head:限定条件,可以当做是传给sleep方法的一个参数
React class组件
我们现在想一下React组件需要实现的功能。首先react是一个对象,需要可以实现html以及相应的js代码。而且一个application是多个组件一起构成的,那么React组件还需要实现组件嵌套过程中的数据交互。
React 组件基本上由 3 个部分组成——属性(props)、状态(state)以及生命周期方法。这里我们从一张图来简单概括 React,如图所示。
React 组件可以接收参数,也可能有自身状态。一旦接收到的参数或自身状态有所改变,React 组件就会执行相应的生命周期方法,最后渲染。整个过程完全符合传统组件所定义的组件职责。
React为什么是这样的结构,我们抛开react,就以原生js来想当前的对象。props是嵌套组件的数据交流。state是组件内部维护的私有变量,用于进行监控当前组件的变化。生命周期以及Render都是内部的方法,这里应该是借鉴web component的customer elements。Render用于渲染html,毕竟这是组件最终要呈现的内容。生命周期则是将组件的变化交给开发者控制。setState方法在我看来就是一种React对于state的保护机制,就好像我们创建对象内的私有变量使用方法去赋值。
类
相似的对象之间往往有一些共同的组成特征。例如麻雀和老鹰都具有鸟类的特征,因此统称为鸟类。上面说的对象,我们称之为是类的一个实例对象。麻雀是鸟类的一个实例对象。
类更多的是称之为一种模板。对象是基于模板的基础上被创建出来的。
不同的是,javascript与c++,java,c#这些传统的面对象语言不同,实际上根本没有类。js的一切都是基于对象的,依靠的是原型系统。
在传统的面向对象的语言中:基于鸟类创建了一个叫麻雀的新对象。
在js基于原型的面向对象语言中:将鸟类对象扩展成一个叫麻雀的新对象。
封装
在js当中提到的更多的词语,封装组件,封装方法。在oop当中,主要用于阐述对象中所包含【或者称之为封装】的内容,通常由两部分构成。
- 相关数据:用于存储属性
- 基于数据所能做的事情:所能调用的方法
我们谈到封装这个属于,实际上还包含了隐藏信息的概念。在oop当中,我们的代码在调用对象的方法的时候,我们基本上是不关心这个方法的内部操作,操作了什么数据。我们关心的是得到的结果是什么。
关于信息隐藏,另一方面也会提到方法和属性的可见性。在java,c++等语言中,我们可以通过public,private,protected关键字来限定可见性。在js当中,所有的方法和属性都是public的,当然我们可以通过一些方法去控制方法和属性的可见性【隐藏性】。例如:闭包
聚合
也称之为组合。实际上就是指哦们将几个现有对象合并成一个新对象的过程,是对于事务的复杂度进行拆分。将复杂的事务拆解为多个小的子对象。然后由多个子对象来构成复杂对象。
继承
通过继承,其实是为了优雅的实现代码的重用。在传统的OOP环境当中,继承通常指的是类与类之间的关系。但是由于js当中不存在类的概念,所以继承只能发生在对象之间。
当一个对象继承自另一个对象的时候,通常会其中添加新的方法,用于扩展被继承的老对象。
B继承自A,对B来说,B可以调用从A继承来的方法,这个时候B可以扩展自己的新方法,也可以对A的方法新增同名的方法,这个重新定义继承方法的过程就叫覆写。
多态
java当中的多态可能比较复杂一些,分为编译时多态,运行时多态。
个人理解:js当中的多态,假设假设A实现了run方法。B继承A,C继承A。B和C都实现了一个run方法,此时属于编译时多态。B和C的方法各自自己定义,执行自己的逻辑。则此时,B,C对A的方法进行了重写,属于编译时多态。
假设我们不知道A和B是定义run方法,当我们对B进行run方法的执行的时候。假如B定义了run方法,则执行B的run方法,假设B没定义,则尝试执行A的run方法,具体当进行执行的时候,才可以知道。
- 编译时多态说的是:继承同一个父类的多个子类
- 运行时多态说的是:具有的继承关系的父子类之间
概念示例:
特征描述 | 概念 |
---|---|
Bob是一个男人 | 对象 |
Bob是一个男性,黑头发 | 属性 |
Bob能吃饭睡觉打豆豆 | 方法 |
Bob是Person类的一个示例 | java中的类 |
Bob是一个由Person对象扩展而来的新对象 | js的原型系统,继承 |
Bob对象中包含了年龄,出生日期,籍贯 | 封装 |
我们不需要知道Bob的年龄如何计算 | 信息隐藏 |
Bob在一家公司上班,包含了一个company对象 | 聚合,组合 |
除了Bob,还有Jill,他们各自的方法不同 | 多态,覆写 |
设计模式是什么
模式是一种可重复使用的解决方法。设计的模式的是三个好处
- 模式是经过验证的解决方案:经过时代发展沉淀出来的解决方案
- 模式可以很容易的重用:开箱即用的方案
- 模式的表达和沟通很富有表现力:因为模式都是具有固定名词和结构,即可优雅解决问题,也可以很好地去进行方法说明和宣讲。
设计模式的重要组成因素
- 模式名称和描述
- 问题陈述:对正在解决的问题陈述,以便我们理解模式的一图。
- 解决方案:在一个可理解的步骤中描述具体的问题是如何解决的。
- 设计:设计模式的描述,特别是用户和相关交互的行为
- 实施:设计模式具体如何实施应用
- 并存条件:是否需要其他的模式进行支持
- 关系:模式是否与其他模式类似,区别和联系是什么?
设计模式分类
创建型设计模式:Creational Design Patterns
- 工厂模式
- 单例模式
- 原型模式
结构型设计模式:Structural Design Patterns
- 适配器模式
- 装饰器模式
- 代理模式
- 外观模式
- 桥接模式
- 组合模式
行为型设计模式:Behavioral Design Patterns
- 观察者模式
- 迭代器模式
- 策略模式
- 模板方法模式
- 职责链模式
- 命令模式
- 备忘录模式
- 状态模式
- 访问者模式
- 中介者模式
- 解释器模式
编程模式和设计模式
下面几种模式是和js语言特性有关的编程模式
- 命名空间:保证全局命名空间不被污染
- 配置对象:下面介绍
- 私有变量和方法:闭包处理
- 特权方法:闭包处理之后,暴露出来进行和外界交互的方法,将对象的内部属性更新通过可控的方法暴露出去。
- 私有函数公有化:闭包处理
- 自执行方法:另一种保证全局遍历不被污染
- 链式调用:通过连用调用可以在单行代码总一次性调用多个方法,就好像被链接在了一起,带来了极大的便利。
- JSON:JSON的使用,进行前后端数据的传递和接受,JSON是一种流行,与语言无关的数据交换格式。
配置对象
当我们的方法存在很多的参数的时候,也就是当参数多余三个的时候,使用起来就会很不方便,尽可能通过对象来处理。
通过对象来代替参数的优势:
- 不用考虑参数的顺序
- 可以跳过某些参数的设置
- 函数的扩展性更强
- 代码的可读性很好,我们可以通过属性名来确定具体含义
设计原则SOLID
首先说明一下,对于设计原则的理解不是很深刻,但是这里还是会介绍一下。
S单一职责原则
该设计原则是基于康威定律的一个推论——一个软件系统的最佳结构高度依赖于开发这个系统的组织的内部结构。这样每个软件模块有且只有一个需要被改变的理由。
这个在js运用当中,着重表现为,对于方法和实体的业务边界是什么,如何划分业务边界创建对应的对象。以及内部的方法划分。
O开闭原则
该设计原则是由Bertrand Meyer在20世纪80年代大力推广的,其核心要素是:如果软件系统想要更容易被改变,那么其设计就必须允许新增代码来修改系统行为,而非只能靠修改原来的代码。
- 开发:扩展
- 关闭:修改
以react class组件举例:组件既定的逻辑是确定,声明周期是确定,我们可以扩展自己的方法去处理具体的业务逻辑,新增对应JSX语言进行页面展示,这些都是组件本身支持的扩展。对于数据的修改,通过setState进行了数据修改造成重新渲染的途径。指的是上面编程模式当中的特权方法。
L里氏替换原则
该设计原则是Barbara Liskov在1988年提出的一个著名的子类型定义。简单来说,这项原则的意思是如果想用可替换的组件来构建软件系统,那么这些组件就必须遵守同一个约定,以便让这些组件可以相互替换。
关于这里在js当中的运用:可以查看汤姆大叔的文章
I接口分离原则
该项设计原则主要告诫软件设计师应该在设计中避免不必要的依赖。
不应该强迫客户依赖于它们不用的方法。在js当中指的是方法。
D依赖反转原则
该设计原则指出高层策略性的代码不应该依赖实现底层细节的代码,恰恰相反,那些实现底层细节的代码应该依赖高层策略性的代码。其实还是为了解耦。具体这个原则,我会在下面的文章中介绍一下:设计一个简单版本的店铺装修组件。
依赖倒置原则的最重要问题就是确保应用程序或框架的主要组件从非重要的底层组件实现细节解耦出来,这将确保程序的最重要的部分不会因为低层次组件的变化修改而受影响