JavaScript 设计模式的七大原则(未完成)
设计模式(面向对象)有七大设计原则,分别是:
开闭原则:对扩展开放,对修改关闭
单一职责原则:每一个类应该专注于做一件事情
里氏替换原则:父类存在的地方,子类是可以替换的
依赖倒转原则:实现尽量依赖抽象,不依赖具体实现
接口隔离原则
合成服用原则
迪米特法原则
一、开闭原则
开闭原则是面向对象设计中最基础的设计原则。
对扩展开放:这意味着模块的行为是可以扩展的。当应用的需求改变时,可以对模块进行扩展,使其具有新的功能满足需求的变化。
对修改关闭:不允许对实体做任何修改,就是这些需要执行多样行为的实体应该设计成不需要修改就可以实现各种的变化,坚持开闭原则有利于用最少的代码进行项目维护。
举个栗子
需求:商品列表中,如果是男装类型,商品背景色使用蓝色 ,点击之后弹出男装价格;如果是女装,商品背景色使用红色,点击后弹出女装品牌。
以下为代码示范:
普通代码我们会这么做:
// 渲染html的函数中
if (commodity.type === '男装') {
commodity.css(background, blue);
} else {
commodity.css(background, red);
} // 点击事件的函数中
if (commodity.type === '男装') {
// 弹出价格
alert(commodity.price);
} else {
// 弹出品牌
alert(commodity.brand);
}
看起来一切都很好,代码上线了。过了一阵,PM告知添加一种商品类型,童装,商品背景色使用黄色,点击之后弹出童装的销量。
那么,代码会被改成下面这样:
// 渲染html的函数中
if (commodity.type === '男装') {
commodity.css(background, blue);
} else if (commodity.type === '女装') { // 修改点1 增加女装类型判断
commodity.css(background, red);
} else { // 修改点2 增加童装html渲染处理
commodity.css(background, yellow);
} // 点击事件的函数中
if (commodity.type === '男装') {
// 弹出价格
alert(commodity.price);
} else if (commodity.type === '女装') { // 修改点3 增加女装类型判断
// 弹出价格
alert(commodity.brand);
} else { // 修改点4 增加童装点击处理
// 弹出销量
alert(commodity.sales);
}
ok,以上是可能的代码编写方式,当需求发生变化时,会对原有代码很多地方进行修改,因为修改的地方过于琐碎,修改后。心里一定会慌慌的,同时修改过程也好火眼金睛,生怕漏掉某一处代码,代码可想而知。
下面我们看一下符合开闭原则的代码:
// getManager的实现
function getManager(commodity) {
if (commodity.type === '男装') return MaleManager;
if (commodity.type === '女装') return FemaleManager;
} let MaleManager = {
Settingbackground: function () {
commodity.css(background, blue);
},
Prompt: function () {
// 弹出价格
alert(commodity.price);
}
}; let FemaleManager = {
Settingbackground: function () {
commodity.css(background, red);
},
Prompt: function () {
// 弹出品牌
alert(commodity.brand);
}
};
ok,代码量好像多了,多了好几个对象和方法。。。我们接着往下看,当需求发生了变化,童装出现的时候,代码如下:
// getManager的实现
function getManager(commodity) {
if (commodity.type === '男装') return MaleManager;
if (commodity.type === '女装') return FemaleManager;
if (commodity.type === '童装') return ChildManager; // 修改点1 添加童装管理器的路由,此处可以利用约定的方式而不用修改,后面再讲
} let MaleManager = {
Settingbackground: function () {
commodity.css(background, blue);
},
Prompt: function () {
// 弹出价格
alert(commodity.price);
}
}; let FemaleManager = {
Settingbackground: function () {
commodity.css(background, red);
},
Prompt: function () {
// 弹出品牌
alert(commodity.brand);
}
}; // 修改点2 添加童装管理器,此处其实不算修改,是新增一个对象
let ChildManager = {
Settingbackground: function () {
commodity.css(background, yellow);
},
Prompt: function () {
// 弹出销量
alert(commodity.sales);
}
};
我们可以看到,按照开闭原则设计后的代码,修改点只有一处,修改的地方也可以预判,修改路由方法getManager即可(此处修改其实可以避免);然后新增一个童装manager即可。
二、单一职责原则
就一个类而言,应该仅有一个引起它变化的原因。
我们在做编程的时候,很自然的会在一个类上加上各种各样的功能。这意味着,无论任何需求要来,只需要修改这个类,这样其实是糟糕的,维护麻烦,复用不可能。单一职责就是每个类型功能要求单一,一个类只负责干一件事,类的可读性提高,复杂度降低;可读性提高了,代码就更容易维护;变更(需求是肯定会变的,程序员都知道)引起的风险(包括测试的难度,以及需要测试的范围)降低。
举一个最普通的例子,比如我们写一个最简单的静态页,我们就会创建一个js文件,一个css文件,一个images文件,我们会把对应的文件类型放到对应的文件夹下面。如果我们需要修改样式,我们就会去css文件夹下面去找需要修改样式的对应css文件,比如我们想添加一张图片我们就会去images文件下去放一张需要添加的图片。这样下来我们进行代码修改或添加的时候也会比较方便,节省开发时间。
代码:
<input type="text" id="ipt">
<script> var ipt = document.getElementById('ipt')
ipt.onclick = function () {
console.log('这是鼠标点击事件!')
}
ipt.ondblclick = function () {
console.log('这是鼠标双击事件!')
}
ipt.onmouseover = function () {
console.log('这是鼠标移入事件!')
}
ipt.onmouseout = function () {
console.log('这是鼠标移出事件!')
}
ipt.onblur = function () {
console.log('这是失去焦点事件!')
}
ipt.keydown = function () {
console.log('这是键盘按下事件!')
}
ipt.keyup = function () {
console.log('这是键盘抬起事件!')
} </script>
比如上面代码,每个事件只执行每个事件对应的代码。
那么单一职责原则的意义何在呢?
- 降低类的复杂性,实现什么样的职责都有清晰的定义
- 提高可读性
- 提高可维护性
- 降低变更引起的风险,对系统扩展性和维护性很有帮助
三、里氏替换原则
通俗的定义:所有引用基类的地方必须能透明地使用其子类的对象。
更通俗的定义:子类可以扩展父类的功能,但不能改变父类原有的功能。
里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,而且功能不受影响时,基类才能真正被复用,而衍生类也能在子类的基础上增加新的功能。(也就是说,任何一个子类的实例都可以替换父类的实例,而功能不受影响)
要遵循里氏替换原则, 需要保证子类在实现父类方法时,必须遵循父类的方法,而且不能重写父类已经定义的方法,可以这样理解继承中父类的关系:
父类中定义的方法,实际上是在设定一系列的规则和契约,虽然它不强制子类必须遵循这些契约,但是如果子类对父类的方法修改,就会对整个继承体系产生破坏。
子类必须完全实现父类的方法
里氏替换原则定义了什么是父子,还有一点要注意的,就是儿子不能在父亲会的技能上搞“创新”。
比如父亲会做红烧排骨,儿子在新东方烹饪学校中学到了一招,在红烧排骨里面加糖和醋,变成红烧糖醋排骨,更加美味,看代码,儿子在父亲的基础红烧排骨上加了糖醋,好像没啥问题。
class Father1 {
braisedRibs() {
console.log("红烧排骨");
} }
class Son1 extends Father1 {
braisedRibs() {
console.log("红烧糖醋排骨");
}
}
运行下面代码,会打印:红烧排骨。
var Father = new Father1();
Father.braisedRibs()
在使用父亲的地方,都能够替换成儿子,并且效果是一样的,那接下来我们改一下代码。
var BigSon = new Son1();
Son.braisedRibs()
结果是啥?打印出:红烧糖醋排骨。 父亲会的东西儿子必须继承下来,在父亲不在的时候儿子必须能顶上,但是儿子不能忘掉继承下来的东西,也不能把继承下来的东西修改成别的,这就不遵循里氏替换。
子类可以有自己的个性
我们来看一下父亲的小儿子,小儿子也在新东方烹饪学校学了个手艺。
class Son2 extends Father1 {
braisedSweetAndSourPorkRibs() {
console.log("红烧甜汤排骨");
}
}
测试一下是不是好儿子
var SmallSon = new Son2();
SmallSonn.braisedRibs()
SmallSonn.braisedSweetAndSourPorkRibs()
打印出:
红烧排骨
红烧糖醋排骨
这才是 父亲 的好儿子嘛,不仅会红烧排骨,还会红烧糖醋排骨。所以说里氏替换原则就是在定义父子关系,大家都遵守这个定义,就会一代比一代好,不遵守大家也看到了,把前辈传下来的都毁于一旦了。
四、依赖倒转原则
定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象
抽象:即抽象类或接口,两者是不能够实例化的
细节:即具体的实现类,实现接口或者继承抽象类所产生的类,两者可以通过关键字new直接被实例化
JavaScript 设计模式的七大原则(未完成)的更多相关文章
- java设计模式之七大原则
java设计模式 以下内容为本人的学习笔记,如需要转载,请声明原文链接 https://www.cnblogs.com/lyh1024/p/16724932.html 设计模式 1.设计模式的目的 ...
- 设计模式的七大原则(Java)
一.OOP三大基本特性 OOP 面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法.模型是用来反映现实世 ...
- JavaScript设计模式之设计原则
何为设计 即按照哪一种思路或者标准来实现功能,功能相同,可以有不同的设计方案来实现 伴随着需求的增加,设计的作用就会体现出来,一般的APP每天都在变化,更新很快,需求不断在增加,如果设计的不好,后面很 ...
- Java设计模式_七大原则
简介 单一职责原则.对类来说,即一个类应该只负责一项职责. 开闭原则.对扩展开放,对修改关闭.在程序需要进行扩展的时候,不能去修改原有代码,使用接口和抽象类实现一个热插拔的效果. 里氏替换原则.任何基 ...
- 设计模式七大原则(C++描述)
前言 最近在学习一些基本的设计模式,发现很多博客都是写了六个原则,但我认为有7个原则,并且我认为在编码中思想还是挺重要,所以写下一篇博客来总结下 之后有机会会写下一些设计模式的博客(咕咕咕...... ...
- Java设计模式(1:软件架构设计七大原则及开闭原则详解)
前言 在日常工作中,我们使用Java语言进行业务开发的时候,或多或少的都会涉及到设计模式,而运用好设计模式对于我而言,又是一个比较大的难题.为了解决.克服这个难题,笔主特别开了这个博客来记录自己学习的 ...
- JavaScript设计模式导学
如何成为一名合格的工程师? 作为一名合格的工程师,不仅需要懂代码,还要懂设计,一名合格工程师的必备条件: 前端开发有一定的设计能力,一般三年开发经验的同学,面试必须考设计能力 成为项目技术负责人,设计 ...
- Java设计模式遵循的七大原则
最近几年来,人们踊跃的提倡和使用设计模式,其根本原因就是为了实现代码的复用性,增加代码的可维护性.设计模式的实现遵循了一些原则,从而达到代码的复用性及增加可维护性的目的,设计模式对理解面向对象的三大特 ...
- 【设计模式系列】之OO面向对象设计七大原则
1 概述 本章叙述面向向对象设计的七大原则,七大原则分为:单一职责原则.开闭原则.里氏替换原则.依赖倒置原则.接口隔离原则.合成/聚合复用原则.迪米特法则. 2 七大OO面向对象设计 2.1 单一 ...
随机推荐
- kafka笔记3(生产者)
创建Kafka生产者: Kafka生产者有3个必选属性: bootstrap.servers broker地址清单,格式为host:port ,清单中不必包含所有broker,但至少2个 ke ...
- Oracle 26表空间的管理
一.查看用户表空间 熟悉与表空间相关的数据字典 查看用户的表空间 相关的数据字典:(用于查询数据库信息的数据库表)dba_tablespaces (管理员级别的表空间的描述信息) User_table ...
- python模块化学习(一)
import time #获取cpu的时间: #获取本地时间: #获取标准时间格式: #获取时间戳: #print(time.clock()) #这个在3即将被舍弃 print(time.proces ...
- DX9 DirectX 索引缓存(IndexBuffer) 代码
// @time: 2012.3.22 // @author: jadeshu // des: 索引缓存 //包含头文件 #include <Windows.h> #include < ...
- ASP.net MVC5 Code First填充测试数据到数据库
问题的产生 最近在看Adam Freeman的“Pro ASP.NET MVC5”,于是在工作机上面搭建了相应的运行环境,但是在自己的机器上面只有代码,没有数据库.记得在code first中可以新 ...
- OAuth 2.0之授权码模式
转载自:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html OAuth 2.0授权码模式 授权码模式(authorization code)是功 ...
- 解决 img 标签上下出现的间隙
我们在平常的开发过程中,经常需要使用多张图片,而使用多张图片的时候,一般会去使用一个列表来对我们的img进行承装.就算我们把img的外边距和内边距全部清空了,但是这时会发现图片上下单会多出一定的间隙. ...
- web文件上传
文件上传的步骤: 1.目前Java文件上传功能都是依靠Apache组织的commons-io, fileupload两个包来实现的: 2. http://commons.apache.org/下载io ...
- Java多态(注意事项)
多态:相同类型的变量.调用同一方法时呈现出多种不同的行为特征,这就是多态. 1.引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法,因此编写Java代码时.引用 ...
- Excel提取设定的多个关键字段
从一段文字中,提取事先设定的关键字段: 在M2单元格输入下列公式: =IFERROR(IF(FIND(O$2,Q2),O$2&" "),"")& ...