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 单一 ...
随机推荐
- python 爬虫-2
小白新手完全不懂的什么,还有一个robots.txt限制文件,稀里糊涂的 还是百度 可以看一下:http://www.baidu.com/robots.txt 里面会有一些限制,常见的一些配 ...
- Qt 拷贝内容到粘贴板 || 获取粘贴板内容
QString source = ui->textEdit_code->toPlainText(); QClipboard *clipboard = QApplication::clipb ...
- C++ 打印机设置
我在网上已不断看到一些网友关于自定义纸张打印的问题,基本上还没有较完美的解决方案,我在这里提供一个WindowsNT/2000/XP下的解决办法,供广大同仁参考.Windows9x/Me下也有解决办法 ...
- 用javaScript获取页面元素值
用JavaScript获取页面元素常见的三种方法: getElementById() ...
- java 常用的异常处理
在Java中异常被当做对象来处理,根类是java.lang.Throwable类,在Java中定义了很多异常类(如OutOfMemoryError.NullPointerException.Index ...
- Dijkstra双栈算术表达式求值
在看algs4的时候偶然发现了这个算法,又回顾了一遍当时数据结构课程里讲过的知识,当时很不在意.迟早是要还的,哎 用python实现了,比较麻烦的是我现在没有解决bash传参的问题,''(" ...
- 剑指offer(41)和为S的连续正数序列
题目描述 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久,他 ...
- springmvc多个视图解析器
<property name="viewResolvers"> <list><!-- 多个视图解析器 --> <bean class=&q ...
- 若快打码平台python开发文档修改版
一.打码的作用 在进行爬虫过程中,部分网站的登录验证码是比较简单的,例如四个英文数字随机组合而成的验证码,有的是全数字随机组成的验证码,有的是全中文随机组成的验证码.为了爬虫进行自动化,需要解决自动登 ...
- CentOS7.3上如何安装Apache/2.4.34
1)卸载系统自带的httpd Centos可能自带了httpd,但是版本可能会较低,执行下面的命令检测是否已经安装了httpd rpm -qa | grep httpd 如果检测已经安装了二进制的ht ...