读书笔记----软件设计原则、设计模式
前言
这个作业属于哪个课程 | 2021软件代码开发技术 |
---|---|
这个作业要求在哪里 | 读书笔记----软件设计原则、设计模式 |
这个作业的目标 | 了解软件设计原则和设计模式,并应用到自己的代码中去 |
读书笔记
书籍详情
软件设计的七大原则
开闭原则
软件实体应当对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification)
- 定义:一个软件实体如类、模块函数应该对扩展开放,对修改关闭。强调的是用抽象构建框架,用实现扩展细节。以提高软件系统的可复用性及可维护性帮助我们实现稳定灵活的系统架构
- 核心思想:面向抽象编程
- 举例:
//小明同学
class XiaoMing {
public name!: string;
public sex!: string;
public age!: number;
}
//小明同学唱歌,错误写法
class XiaoMing {
public name!: string;
public sex!: string;
public age!: number;
public sing() {
// 唱歌
}
}
//小明同学唱歌,正确写法,根据开闭原则进行拓展
class XiaoMingLearn extends XiaoMing {
public sing() {
// 唱歌
}
}
里氏替换原则
继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects)
- 定义:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法
- 举例:正方形不是长方形
依赖倒置原则
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)
- 定义:高层模块不应该依赖低层模块,两者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象
- 核心思想:要面向接口编程,不要面向实现编程
- 举例:
//汽车A拥有run方法
class CarA {
public run () {
// 我跑起来了
}
}
//汽车B也拥有run方法
class CarB {
public run () {
// 我跑起来了
}
}
//司机小明想驾驶汽车A和汽车B,由于汽车A和汽车B不同类,所以属两个drive方法
class XiaoMing {
public driveA (car: CarA) {
car.run()
// 司机小明驾驶汽车A
}
public driveB (car: CarB) {
car.run()
// 司机小明驾驶汽车B
}
}
//根据依赖倒置原则,实现如下
//先创建一个drive接口
interface IDrive {
drive: (car: Car) => {
//驾驶方法
}
}
//小明通过IDrive接口去实现驾驶
class XiaoMing implements IDrive {
drive!: (car: Car) => {
car.run()
//小明学会了驾驶方法
};
}
//再给汽车创建一个通用类,且都可以驾驶
class Car {
public run () {
//可驾驶的方法
}
}
class A extends Car {
public name = 'A车'
}
class B extends Car {
public name = 'B车'
}
//小明驾驶汽车A或者汽车B
class Test {
public driveCar () {
const XiaoMing= new XiaoMing()
xiaogua.drive(new A())
xiaogua.drive(new B())
}
}
单一职责原则
单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分(There should never be more than one reason for a class to change)
- 定义:不要存在多于一个导致类变更的原因
- 举例:一个类/接口/方法只负责一项职责。例如大学学生工作主要包括学生生活辅导和学生学业指导两个方面的工作,正确的做法是生活辅导由辅导员负责,学业指导由学业导师负责,参考如下类图:
接口隔离原则
一个类对另一个类的依赖应该建立在最小的接口上(The dependency of one class to another one should depend on the smallest possible interface)
- 定义:用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口
- 举例:
//小明同学会唱歌会跳舞还会打篮球
class XiaoMing {
public sing() {}
public dancing() {}
public playBasketball() {}
}
//根据接口隔离原则,把唱歌跳舞打篮球分成不同模块
interface ISingAction {
sing: () => {}
}
interface IDancingAction {
dancing: () => {}
}
interface IPlayBasketballAction {
playBasketball: () => {}
}
//当小明需要作出某种行为的时候
class XiaoMing implements ISingAction {
public sing: () => {}
}
class XiaoMing implements IDancingAction {
public dancing: () => {}
}
class XiaoMing implements IPlayBasketballAction {
public playBasketball: () => {}
}
迪米特法则(最少知道原则)
只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers)
- 定义:一个对象对其他对象保持最少的了解,尽量降低类与类之间的耦合,强调只与相关类交流。相关类指的是出现在成员变量、方法的输入、输出参数中的类
- 举例:
//校长需要老师统计班上学生的年龄,校长不需要关心学生的类型,由老师来统计
class Student {
public age!: number;
}
class Teacher {
public countAge() {
const list = [];
for (let i = 0;i < 20; i++) {
list.push(new Student().age)
}
}
}
class Principal {
public commandCountAge(teacher: Teacher) {
teacher.countAge()
}
}
合成复用原则
- 定义:尽量使用对象组合/聚合,而不是继承关系达到软件复用的目的
- 如果要使用继承关系,则必须严格遵循里氏替换原则
- 举例:汽车按“动力源”划分可分为汽油汽车、电动汽车等;按“颜色”划分可分为白色汽车、黑色汽车和红色汽车等。用继承关系实现的类图如下图:
- 从类图中可以看出这显然违背了开闭原则,但如果改用组合关系实现就能很好地解决以上问题,其类图如下图:
小结
- 这些原则的目的只有一个:降低对象之间的耦合,增加程序的可复用性、可扩展性和可维护性。
- 记忆口诀:访问加限制,函数要节俭,依赖不允许,动态加接口,父类要抽象,扩展不更改。
开发实践
本人是学习前端的,现以JavaScript常见的设计模式举例展示
工厂模式
- 工厂模式是软件工程的一种设计模式
- 它抽象了创建具体对象的过程,通过函数(ECMAScript中无法创建类)来封装以特定接口创建对象的细节
- 这种模式解决了创建多个相似对象的问题,可以通过无数次调用函数来创建对象,即工厂模式实际提供了一个创建对象的公共接口
//通过函数封装工人这个对象,内含姓名、年龄和职位
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
//工人的sayName方法
this.sayName = function() {
alert(this.name);
};
}
//新建工人Jack,年龄20,职位是teacher
var person1 = new Person("Jack", 20, "teacher");
//新建工人Tom,年龄22,职位是doctor
var person2 = new Person("Tom", 22, "doctor");
//person1和person2既是Object的实例,也是是构造函数Person的实例
console.log(person1 instanceof Object); //true
console.log(person1 instanceof Person); //true
console.log(person2 instanceof Object); //true
console.log(person2 instanceof Person); //true
//例:调用person1和person2实例中的方法
person1.sayName(); //Jack
person2.sayName(); //Tom
学习体验
- 通过对七大原则的学习,可以更深刻地体会到在软件中对象之间的关系以及如何提高程序的复用性,对日后的开发有很大的帮助
- 如何让原则渗入自己写的代码则是一个需要加强学习的过程