首页 / 设计模式 / 读书笔记—设计原则与设计模式
读书笔记—设计原则与设计模式
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了读书笔记—设计原则与设计模式,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含10450字,纯文字阅读大概需要15分钟。
内容图文
![读书笔记—设计原则与设计模式](/upload/InfoBanner/zyjiaocheng/1036/b1c1210ec7a245b39b670ba35f80bf2f.jpg)
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/2021Softwarecodedevelopmenttechnology/homework/11833 |
这个作业的目标 | 1.了解什么是设计原则及其应用 |
2.了解什么是设计模式 | |
3.巩固Markdown用法 | |
4.养成一个良好的写代码习惯 |
设计原则
1.单一职责原则(SRP)
- 什么是SRP原则呢,原义是:任何一个软件模块中,应该有且只有一个被修改的原因。这句话虽有点难以理解,但翻译过来就是:每个软件模块职责要单一,每一个职责都是变化的一个轴线,同样的如果一个模块有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。而且,多个职责耦合在一起,会影响复用性。那为什么要满足SRP原则呢?我们知道软件设计讲究“高内聚,低耦合”,一个模块它的职责越单一,被修改的原因就越少,那它这个模块的内聚性就越高,正好满足前面的要求,何况这样式的模块复用可能性很高,代码也易读懂,维护难度低。那我们为什么不去满足它呢?
- 满足SRP原则,更是一种写代码的好习惯,值得学习。
2.开闭原则(OCP)
- 开闭原则讲究软件实体应该对外扩展开放,对修改关闭。
对扩展开放,意味着有新的需求或变化是,可以对现有的代码进行扩展(不是修改)来适应新状况;
对修改关闭,意味着类一旦设计完成,就可以独立完成工作,不要对其进行任何的修改。
也可以这样理解由于我们对扩展实现了开放,才能够保证对修改是封闭的。开放利用了对象的抽象,封闭则在一定程度上利用了封装。最佳的做法仍然是要做到分离对象的变与不变,将对象不变的部分封装起来,并遵循良好的设计原则以保障接口的稳定;至于对象中可能变的部分,则需要进行抽象,以建立松散的耦合关系。而要实现OCP一般来讲是通过继承和多态,适用的设计模式有:装饰者模式,策略模式,适配器模式,观察者模式。 - 我们对OCP如此重视的原因是一个指标,一个梦想。一个指标是“可扩展性是我们衡量软件质量的一个重要指标”;一个梦想“在软件生命周期内,能有一种方案,既可以扩展软件功能,又可以不修改原代码”。有这个梦想的原因也是"BUG"的原因,如果一个类已经可以完美运行,这时候新增一个需求,让你改代码,这时候你去修改原代码,报错的可能性很大,修改浪费的时间也很长。但如果能不修改就能扩展,不修改就不会影响现有需求,新增的代码也不会对原需求产生影响,时间省下了,效率提高了,项目进度也快了。
3.里氏替换原则(LSP)
- LSP认为“程序中的对象应该是可以在不改变程序正确性的前提下被它的子类所替换”也就是说子类可以替换任何基类能够出现的地方,而且之后代码还能正常工作。
- 解决办法
(1)子类可以实现父类的方法,但是不要覆盖(重写)父类的方法。
(2)子类可以增加自定义的方法(可以拓展方法)
(3)当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
(4)当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
实现LSP可以大大的减少程序的bug和增加程序的可读性
4.接口隔离原则(ISP)
- ISP认为使用多个专门的接口比使用单一的总接口要好。
客户端不应该依赖它不需要的接口
类间的依赖关系应该建立在最小的接口上 - 用土话来讲,鸡蛋不要放一个篮子打死,狡兔还有三窟呢,
你在一个接口里面放很多的方法,这样会显得这个类非常臃肿不堪。所以我们接口应该尽量细化,一个接口应该对应一个功能模块,同时接口里面的方法也应该尽可能的少,让接口更加轻便灵活。也就是每一个模块对应一个接口。 - 而且如果使用"ISP"那木首先得满足“SRP”,但是接口隔离原则和单一职责原则看起来很相似但本质还有些差别,单一职责原则要求类和接口职责单一,它注重的是类的职责,是业务逻辑上的划分;而接口隔离原则要求方法要尽可能的少,是在接口设计上的考虑。
5.依赖倒置原则(DIP)
- DIP要求
高层模块不应该依赖低层模块,两者都应该依赖其抽象
抽象不应该依赖细节
细节应该依赖抽象 - 什么是低层模块呢?低层模块就是不可分割的原子逻辑,而每一个逻辑的实现都是原子逻辑,一般可能是接口也可能是抽象类。而原子逻辑组装起来也就成了高级模块。
- 在面向接口编程中,类不是孤立的,一个类需要依赖于其他类来协作完成工作,但是这种依赖不是特定的具体实现,而应该依赖抽象。比如,原神它是一个pc和手游互通的游戏,那木为什么它能互通呢,那是因为它两个端口都依赖于同一个抽象,满足平台的上线协议。
- 优点:减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。
设计模式
- 什么是设计模式?
设计模式是一套代码设计经验的总结,并且该经验必须能被反复使用,被多数人认可和知晓,设计模式描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案,具有一定的普遍性,可以反复使用。其目的是提高代码的可重用性,可读性和可靠性
设计模式的本质是面向对象设计原则的实际应用,是对类的封装性,继承性和多态性,以及类的关联关系和组成关系的充分理解。 - 什么是模式?
模式不是框架,也不是过程。模式不是简单的“问题的解决方案”,必须是典型问题的解决方案,是可以让学习者举一反三的,是理论和实践之间的中介环节、它具有一般性、简单性、重复性、结构性、稳定性和可操作性等特征。模式是不能套用的,必须结合具体情况的上下文使用。设计模式不是必备的,必用,但是必须了解知道的“工具”
1.创建者模式
- 创建型模式主要用于描述“怎样创建对象”,主要特点是“将对象的创建和使用分离”,包含:单例,原型,工厂方法,抽象工厂,建造者5种创建型模式。
1.1 单例模式
- 单例模式(Singleton):某个类只能生成一个实例,该类例子提供了一个全局访问点,以便外部获取该实例,其扩展是有限多例模式。总结起来就是“在符合开放封闭原则的情况下,有且只有一个实例,并提供给全局访问接口”
- 这里引用《JavaScript设计模式与开发实践》的登录框例子进行理解
<!DOCTYPE html>
<html lang="en">
<body>
<button id="btn">登录</button>
</body>
<script>
class Login {
createLayout() {
var oDiv = document.createElement('div')
oDiv.innerHTML = '我是登录框'
document.body.appendChild(oDiv)
oDiv.style.display = 'none'
return oDiv
}
}
class Single {
getSingle(fn) {
var result;
return function() {
return result || (result = fn.apply(this, arguments))
}
}
}
var oBtn = document.getElementById('btn')
var single = new Single()
var login = new Login()
// 由于闭包,createLoginLayer对result的引用,所以当single.getSingle函数执行完之后,内存中并不会销毁result。
// 当第二次以后点击按钮,根据createLoginLayer函数的作用域链中已经包含了result,所以直接返回result
// 讲获取单例和创建登录框的方法解耦,符合开放封闭原则
var createLoginLayer = single.getSingle(login.createLayout)
oBtn.onclick = function() {
var layout = createLoginLayer()
layout.style.display = 'block'
}
</script>
</html>
从这段代码中,我们获取什么也体会不到,我也是。但我们不妨从外部想一想,顾明思义,单例!单例!只有对象只需要一个的时候才适用的模式。我们每次登陆微信时,它的登陆框是唯一的吗?它是唯一的,不管我们点击登陆多少次,除非密码错误那木它只会出现一次,这不正好符合单例模式的内容吗?用单例模式恰好能解决这种单个对象的例子访问接口的混乱问题。
- 单例模式的核心我觉得就是“在满足开放封闭原则的情况下,判断实例是否被创建,创建了就返回,没有就是创建再进行判断。”单例模式是一种方案,是一种思想,而不是一段固定的代码
1.2 工厂模式
- 定义一个用于创建产品的接口,由子类决定生产什么产品。
什么是工厂,工厂是生产产品的,这个产品具有多样性,可能是袜子、书包、鞋、衣服等。而工厂模式也是一种抽象层面的工厂,它的接口主要是为了解决多种相似问题的适用同一种的解决方案,但在这个过程中,你不知道这个“产品”(对象)到底是什么,具有一种神秘感,讲究一个普遍,适应度高。
function CreatePerson(name,age,sex) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.sayName = function(){
return this.name;
}
return obj;
}
var p1 = new CreatePerson("longen",'28','男');
var p2 = new CreatePerson("tugenhua",'27','女');
console.log(p1.name); // longen
console.log(p1.age); // 28
console.log(p1.sex); // 男
console.log(p1.sayName()); // longen
console.log(p2.name); // tugenhua
console.log(p2.age); // 27
console.log(p2.sex); // 女
console.log(p2.sayName()); // tugenhua
// 返回都是object 无法识别对象的类型 不知道他们是哪个对象的实列
console.log(typeof p1); // object
console.log(typeof p2); // object
console.log(p1 instanceof Object); // true
在这段代码中:函数CreatePerson能接受三个参name,age,sex,可以无数次调用这个函数,每次返回都会包含三个属性和一个方法的对象。在函数不变的情况下,可以创建多个“人”进行输出,而不影响原函数,这也符合开放封闭原则。
- 我认为工厂模式符合开放封闭原则,但在这个原则的基础上更有一种固定模式的成分,就像流水线一样解决多相似化的问题,以此减少代码开发难度。
2.行为者模式
- 行为者模式用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责。如:策略、命令、责任链、状态、观察者吗、迭代器模式等
2.1 策略模式
- 定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
var fnA = function(val) {
return val * 1
}
var fnB = function(val) {
return val * 2
}
var fnC = function (val) {
return val * 3
}
var calculate = function(fn, val) {
return fn(val)
}
console.log(calculate(fnA, 100))// 100
console.log(calculate(fnB, 100))// 200
console.log(calculate(fnC, 100))// 300
? 在这一段代码中,我们可以看到,我们将一些简单的算法封装成了单另的函数,fnA,B,C,每当有需要某个算法的时候就进行调用对应的算法实现函数。也就是说在策略模式中,算法的实现和使用是分开的,我将它分为两个部分,一部分我称为“方法s”主要包含各种算法的实现代码,不包含数据等;另一半叫“请求s”,每当有新请求要使用某个算法时,这一部分代码将请求传递并调用对应算法的实现部分,组成输出继续进行传递。
2.2 观察者模式
- 多个对象间存在一对多关系,当一个对象发生改变是,把这种改变通知给其他多个对象,从而影响其他对象的行为。就像中国这个整体,所有国人都依赖它生活,在这个社会主义共和国中,讲究一方有难,八方支援,这个一方就是那个发生改变的对象,这个八方就是其他多个对象。
- 同时观察者模式也叫“发布-订阅模式”看这段代码
// 订阅
document.body.addEventListener('click', function() {
console.log('click1');
}, false);
document.body.addEventListener('click', function() {
console.log('click2');
}, false);
// 发布
document.body.click(); // click1 click2
?每有一个订阅者进入,系统类似公告的东西给用户,相当于一个回复功能。
3.结构型模式
- 结构型模式用于描述如何将类或对象按某种布局组成更大的结构,如:代理、适配器模式等,这里讲一下代理模式
代理模式
- 代理模式为某一对象提供一种代理以控制对该对象的访问,即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。所谓代理我认为可以理解为一个秘书,帮助老板完成一些工作,增加效率,减小成本。让“秘书”
- 举一个使用代理对象加载图片的例子来理解代理模式,当网络不好的时候,图片的加载需要一段时间,这就会产生空白,影响用户体验,这时候我们可在图片真正加载完之前,我们使用一张loading占位图片,等图片真正加载完再给图片设置src属性。
class MyImage {
constructor() {
this.img = new Image()
document.body.appendChild(this.img)
}
setSrc(src) {
this.img.src = src
}
}
class ProxyImage {
constructor() {
this.proxyImage = new Image()
}
setSrc(src) {
let myImageObj = new MyImage()
myImageObj.img.src = 'file://xxx.png' //为本地图片url
this.proxyImage.src = src
this.proxyImage.onload = function() {
myImageObj.img.src = src
}
}
}
var proxyImage = new ProxyImage()
proxyImage.setSrc('http://xxx.png') //服务器资源url
?如果有一天不需要预加载了,我们可以直接使用本体对象的setSrc方法,,并且不需要改动本体类的代码,而且可以删除代理类。这也说明代理模式满足开放封闭原则。
- 总结“在符合开放封闭原则的情况下创建一个代理对象辅助完成工作,且本体对象和代理对象拥有相同的方法,这个对用户是隐藏的”
内容总结
以上是互联网集市为您收集整理的读书笔记—设计原则与设计模式全部内容,希望文章能够帮你解决读书笔记—设计原则与设计模式所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。