携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情。
面向对象
面向对象(Object Oriented)是对世界物件的抽象和封装,它不单纯是代码的组织形式,更是一种思想。
特点
- 封装:定义一个有方法和属性的对象
- 继承:在某个对象的基础上定义自己的方法和属性
- 多态:在某个对象的基础上重新定义某些方法和属性
组合
继承和组合都是为了实现复用,继承是 is-a 的关系,组合式 has-a 的关系。
建议使用组合而非继承。因为继承的耦合性要大于组合,组合更加灵活。我们可以使用多个组合来组织代码,但是多重继承的复杂性会大大增加。
面向对象编程(OOP)的设计模式
单例模式
全局只有一个实例(单例),获取时先判断有无实例,没有则实例化一个,有则返回
- JS 没有私有属性,所以这个单例是可破坏的(外部赋值)
- JS 的 Object 本身就是单例,可以通过它来设置
class Log {
constructor() {}
print() {
console.log('..........')
}
}
let myLog = {
aLog: null,
get() {
if (!this.aLog) {
this.aLog = new Log();
this.aLog.print();
}
return this.aLog;
}
}
策略模式
将变化的部分(属性、方法)等当作策略封装,根据不同类型映射到不同的策略
- 相对于 if-else、switch-case 等,在添加或减少策略时,只需要增删类型,而不用改动 if-else、switch-case 的逻辑
- 体现了开闭原则:对修改是封闭的,而对扩展是开放的
let popType = {
success: {
text: 'log success'
},
fail: {
text: 'log fail'
}
}
let resultType = 'success';
console.log(popType[resultType].text);
观察者模式
观察者向被观察者订阅消息,一旦被观察者发生变化,就会通知观察者进行处理。
- 有点类似于 React 的父子组件,props 更新则子组件重新渲染
// 被观察者
class Observed {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
notify() {
this.observers.forEach(observer => {
observer.update(this);
});
}
}
// 添加观察者
let mObserved=new Observed();
let mObserver1=new Observer();
let mObserver2=new Observer();
mObserved.addObserver(mObserver1);
mObserved.addObserver(mObserver2);
mObserved.notify();
适配器模式
比如大屏和小屏展示的分页样式不一样,适配器会对外提供统一的展示接口,在展示接口内根据屏幕大小展示不同分页样式。对于使用者来说,它不需要关心当前屏幕大小,而是由适配器去处理。
工厂模式
由工厂来负责创建对象,使用者不关心它是怎么创建的。
外观/门面模式
比如展示搜索结果时需要执行显示新结果、更新分页等多个操作,可以用一个模块进行封装,对于使用者来说,它只需调用展示搜索结果的接口,不关心内部执行了什么操作来展示。
状态模式
不同的状态由不同的表现行为,通过状态去驱动 DOM 的更改。
- React 的原型
- 和策略模式形式相同,区别在于它们的意图。策略模式会控制对象使用什么策略,而状态模式会自动改变状态。
代理模式:
React 的行为。不直接操作 DOM,委托 State 和虚拟 DOM 去操作真实的 DOM。
装饰者模式
将多个不相关的操作拆分开来,依次执行(装饰),以便让逻辑更清晰。
- 会增加系统复杂性,不够简单
总结:
在日常开发的过程中,我们应该坚持以下几点:
- 把共性和特性分离(把会变和不变的分离)
- 少用继承,多用组合
- 低耦合,高聚合
- 坚持开闭原则:对修改是封闭的,而对扩展是开放的
- 坚持单一职责原则
- 能用简单的方式就用简单的方式解决
- 提倡面向对象编程,因为它对拓展是有利的