前端设计模式应用
什么是设计模式?
简单来说就是软件设计中常见问题的解决方案模型
常见问题:就是历史经验的总结
解决方案模型:与特定语言无关
设计模式分类
23 种设计模式
- 创建型 - 如何创建一个对象
- 结构型 - 如何灵活的将对象组装成较大的结构
- 行为型 - 负责对象间的高效通信和职责划分
浏览器中的设计模式
单例模式
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例,经常在缓存,全局状态管理等应用场景中使用。
在前端中最常见的单例模式就是window对象,我们在任何一个地方都能够访问到它,并且在任何一个地方的修改在另外任何一个使用它的地方体现。
单例模式应用
class Person {
instance = null;
constructor() {
this.name = "张三";
this.age = 20;
}
static getInstance = () => {
if (this.instance) {
return this.instance;
} else {
this.instance = new Person();
return this.instance;
}
};
}
const p1 = Person.getInstance();
const p2 = Person.getInstance();
console.log(p2.name);
p1.name = "李四";
console.log(p2.name);
console.log(p1, p2);
其核心思想在于,每次创建实例,返回的都是同一个实例,每次调用request返回的都是同一个cache对象
发布订阅模式
发布订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。
从系统架构之间的解耦,到业务中一些实现模式,像邮件订阅,上线订阅等等,应用广泛。
实际上,只要我们曾经在 DOM 节点上面绑定过事件函数,那我们就曾经使用过发布订阅模式。例如我们在空白页面某处执行了点击操作,不管你点的地方有没有按钮,他都会触发许多事件,一次鼠标点击可以触发mousedown、mouseup以及click等等等等事件。但我们都知道,点击空白处是不会发生任何响应的,这是因为我们没有给这个操作绑定相关的订阅者,或者说没有人关心你点击空白处是为了干什么。
发布订阅模式应用
class test {
constructor() {
this.message = {}; //消息队列
}
// 订阅消息
$on(type, callback) {
if (!this.message[type]) {
this.message[type] = [];
}
this.message[type].push(callback);
}
// 取消订阅
$off(type, callback) {
if (!this.message[type]) return;
if (!callback) {
this.message[type] = undefined;
return;
}
this.message[type] = this.message[type].filter((item) => item !== callback);
}
// 触发事件
$emit(type) {
if (!this.message[type]) return;
this.message[type].forEach((item) => {
item();
});
}
}
JavaScript 设计模式
原型模式
原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一,即复制已有的对象来创建新的对象,js中的原型链就与之有关。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
const baseUser = {
/* ... */
}
const user = Object.create(baseUser)
通过Object.create来创建一个新的对象,新的user对象与baseUser是继承关系,可以在user中进行初始化,这两个对象是相互独立的,不相互影响。
代理模式
-
在代理模式中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
-
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
应用实例:
- Windows 里面的快捷方式。
- 猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。
- 买火车票不一定在火车站买,也可以去代售点。
- 一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。
const createProxyUser = (name) => {
const user = new User(name);
const proxyUser = new Proxy(user, {
set: (target, prop, value) => {
target[prop] = value;
/* ... */
return true;
},
});
};
迭代器模式
在不暴露数据类型的情况下访问集合中的数据
使用场景:
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 需要为聚合对象提供多种遍历方式。
- 为遍历不同的聚合结构提供一个统一的接口。
前端框架中的设计模式
代理模式
与JavaScript中的代理模式不同,与其迭代器模式有些类似。
例如Vue中定义的ref变量,它经过一层编译,当该变量变化时,页面上立刻会渲染出新的数据。
用JavaScript我们通常是绑定一个事件,当事件发生时用innerHTML手动去修改页面中的值,后来有了Vue之后,带来了虚拟DOM的环节,对原始的真实DOM做了代理,页面的渲染完全自动化了。
组合模式
组合模式,又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
React 的组件结构
export const Count = () => {
const [const, setCount] = useState(0);
return {
<button onClick={() => setCount((count) => count + 1)}>
count is: {count}
</button>
}
}