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 单一 ...
随机推荐
- 第三章 jQuery事件和动画
1.什么是事件:事件指的是用于对网页操作的时候,网页做出的一个回应. 2.JQuery中的事件:JQuery事件是对JavaScript事件的封装,常用事件的分类如下:(1)基础事件:window事件 ...
- .Net 多线程 (1) Task
多线程是一种有效提高程序工作效率的方法.当然为了效率需要使用更多的cpu,内存等资源. 并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机,如果串行,一个队列使用一台咖啡机,那么哪怕前 ...
- html5 javascript 事件练习1
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- Python之循环
目标 程序的三大流程 while 循环基本使用 break 和 continue while 循环嵌套 一 程序的三大流程 在程序开发中,一共有三种流程方式: 顺序 —— 从上向下,顺序执行代码 分支 ...
- docker基本管理
一.docker基本命令 1.docker 获取镜像 将从 Docker Hub 仓库下载一个 Ubuntu 12.04 操作系统的镜像 docker pull ubuntu:12.04 Pullin ...
- AFNetworking的简单使用
AFNetworking的下载地址: https://github.com/AFNetworking/AFNetworking AFNetworking的使用非常简单,创建一个类,调用一个方法就可以达 ...
- ArchLinux 无密码Samba 配置
安装上迅雷后就必须把硬盘挂上去开个Samba,然后边下电影边看,这就是一个Nas了. 开搞! pacman -S samba 安装samba,然后进入/etc/samba/目录 vim smb.con ...
- Static需谨慎
Static Cling Sticking Your Code To Things Unnecessarily Static Cling is a code smell used to describ ...
- Learning-Python【0】:Windows环境下Python2和Python3的安装
一.下载 可以在官网下载最新版本, 也可以在以下链接中找想安装的版本下载下来,这里以Python3.6和Python2.7为例 https://www.python.org/ftp/python/ 二 ...
- spring初体验 一之helloworld
今天开始学习spring,每天都会将自己学习的一些内容,或是一些总结以博客的形式记录下来,方便自己以后回顾,如果能给他人学习带来丁点的帮助那也是最好不过了.本系列博文的spring学习是基于4.0版本 ...