设计模式需要注意的几大原则
设计原则是设计模式的指导理论,它通常包括:单一功能
,开放封闭
,里式替换
,接口隔离
,依赖反转
五大原则,但是实际中我们常常需要注意的,仅仅是里面的单一功能
,开放封闭
。
通常我们都希望写的代码不用去迭代更新,这样可以“不考虑”代码的健壮性和维护性,只要能够实现功能,就可以了,但是在实际开发过程中,无论是什么样的需求,都会迭代更新,所以就需要让代码易读,易于维护,拒绝“流水账式写法”。这个迭代更新的过程就是变化,我们就需要通过封装变化
的方式来使代码变得简洁,而这也是设计模式的核心思想,以确保变化部分足够灵活,不变的部分足够稳定
。
《设计模式:可复用面向对象软件的基础》这本书中,阐述了设计模式领域的开创性成果将23种设计模式按照“创建型”、“行为型”和“结构型”进行划分:
- 创建型:1.单例模式、2.原型模式、3.构造器模式、4.工厂模式、5.抽象工厂模式
- 结构型:1.桥接模式、2.外观模式、3.组合模式、4.装饰器模式、5.适配器模式、6.代理模式、7.享元模式
- 行为型:1.迭代器模式、2.解释器模式、3.观察者模式、4.中介者模式、5.访问者模式、6.状态模式、7.备忘录模式、8.策略模式、9.模版方法模式、10.职责链模式、11.命令模式
可以从模式名称看出,这23种设计模式都进行了封装变化
:
创建型模
式封装了创建对象过程中的变化
,它做的事情就是将创建对象的过程抽离
结构型模式
封装的是对象之间组合方式
的变化,目的在于灵活地表达对象间的配合与依赖关系
行为型模式
将对象千变万化的行为进行抽离
,确保我们能够更安全、更方便地对行为进行更改
例如如果我们录入少量用户信息时候,可能会直接定义参数式,但是数量多了就会显得代码量过于庞大,难以维护:
const user_1 = { name: '张三', age: 30, career: 'Python' }
const user_2 = { name: '李四', age: 31, career: 'JavaScript' }
const user_3 = { name: '王五', age: 32, career: 'Java' }
...
在上面的这个代码片段中,我们可以识别出,哪些是变化的“个性”,哪些是不变的“共性”,我们可以先使用构造函数
的方式改造上面的代码片段
function User(name, age, career){
this.name = name
this.age = age
this.career = career
}
const user_1 = new User('张三', 30, 'Python')
const user_2 = new User('李四', 31, 'JavaScript')
const user_3 = new User('王五', 32, 'Java')
...
其实上面的User就是一个构造器
,在这个构造器中,将 name, age, career 三个共性的字段封装在了创建用户的过程中,同时开放赋值,取值。
简单的工厂模式
需求:现在在上面的代码中,将用户职责范围的工作进行描述,添加它的特殊标识。
部分开发者的第一反应可能会是创建多个构造器,如下:
function User_Python(name, age){
this.name = name
this.age = age
this.career = 'Python'
this.job = {
start: '10:30',
end: '19:30',
work: ['Python code', 'Python bug fix']
}
}
function User_JavaScript(name, age){
this.name = name
this.age = age
this.career = 'JavaScript'
this.job = {
start: '10:30',
end: '19:30',
work: ['JavaScript code', 'JavaScript bug fix']
}
}
function User_Java(name, age){
this.name = name
this.age = age
this.career = 'Java'
this.job = {
start: '10:30',
end: '19:30',
work: ['Java code', 'Java bug fix']
}
}
function Factory(name, age, career){
switch(career) {
case 'Python':
return new User_Python(name, age)
break
case 'JavaScript':
return new User_JavaScript(name, age)
break
case 'Java':
return new User_Java(name, age)
break
...
}
}
const user_1 = new Factory('张三', 30, 'Python')
const user_2 = new Factory('李四', 31, 'JavaScript')
const user_3 = new Factory('王五', 32, 'Java')
我们通过上面的代码,可以看出,在构造器中,有大量冗余代码,如果要在每个用户信息添加公司名称,需要在多个构造器中都添加。我们可以将共性参数抽出来,对个性参数进行处理:
function User(name, age, career, job){
this.name = name
this.age = age
this.career = career
this.job = job
}
function Factory(name, age, career){
let job = []
switch(career) {
case 'Python':
job = ['Python code', 'Python bug fix']
break
case 'JavaScript':
job = ['JavaScript code', 'JavaScript bug fix']
break
case 'Java':
job = ['Java code', 'Java bug fix']
break
...
}
return new User(name, age, career, job)
}
const user_1 = new Factory('张三', 30, 'Python')
const user_2 = new Factory('李四', 31, 'JavaScript')
const user_3 = new Factory('王五', 32, 'Java')
这样看来,不仅代码冗余降低了,可读性也变强了,由此看来,当创建对象时候,如果有多个共性与个性时候,可以优先考虑使用工厂模式,由此来降低开发成本。