个人简介
个人主页: 前端杂货铺
♂️学习方向: 主攻前端方向,正逐渐往全干发展
个人状态: 研发工程师,现效力于中国工业软件事业
人生格言: 积跬步至千里,积小流成江海
推荐学习:前端面试宝典 Vue2 Vue3 Vue2/3项目实战 Node.jsThree.js JS版算法
个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧
内容 | 参考链接 |
---|---|
JavaScript设计模式(一) | 构造器模式、原型模式、类模式 |
JavaScript设计模式(二) | 简单工厂模式、抽象工厂模式、建造者模式 |
JavaScript设计模式(三) | 单例模式、装饰器模式、适配器模式 |
大家好,这里是前端杂货铺。
上一节,我们学习了策略模式、代理模式、观察者模式。这一节,我们学习发布订阅模式、桥接模式和组合模式…
观察者和目标要互相知道,发布者和订阅者 不用相互知道,通过第三方实现调度,属于 经过解耦合的 观察者模式。
我们定义 PubSub 类(发布订阅),里面的 message 对象用于存放要订阅的信息。
subscribe 方法期待两个参数(type 和 cb),type 表示要订阅的类型,cb 表示订阅的详细信息,直接把 cb 赋值给 type 即可。
publish 方法也期待两个参数(type 和 data),如果发布的时候没有该类型,则直接 return,否则发布出该类型。
unsubscribe 同 subscribe 一样,期待两个参数,用于取消订阅。
class PubSub {
message = {};
// 发布
publish(type, data) {
// 发布的时候没有该类型,直接 return
if (!this.message[type]) return;
this.message[type].forEach(item => item(data));
}
// 订阅
subscribe(type, cb) {
this.message[type] = [cb];
}
// 取消订阅
unsubscribe(type, cb) {
// 取消订阅的时候如果没有该类型,直接 return
if (!this.message[type]) return;
if (!cb) {
this.message[type] && (this.message[type].length = 0);
} else {
this.message[type] = this.message[type].filter(item => item !== cb);
}
}
}
// 创建 pubsub 实例
const pubsub = new PubSub();
function milk(data) {
console.log('milk', data);
}
function apple(data) {
console.log('apple', data);
}
function chicken(data) {
console.log('chicken', data);
}
// 订阅 牛奶、苹果、大盘鸡
pubsub.subscribe('milk', milk);
pubsub.subscribe('apple', apple);
pubsub.subscribe('chicken', chicken);
// 发布 牛奶、苹果、大盘鸡
pubsub.publish('milk', '牛奶');
pubsub.publish('apple', '苹果');
pubsub.publish('chicken', '大盘鸡');
console.log('分-----割-----线')
// 取消对大盘鸡的订阅
pubsub.unsubscribe('chicken');
// 发布 牛奶、苹果、大盘鸡(大盘鸡不会被发布,因为被取消订阅了)
pubsub.publish('milk', '牛奶');
pubsub.publish('apple', '苹果');
pubsub.publish('chicken', '大盘鸡');
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
使用场景:一个类存在两个或多个独立变化的维度,且这两个维度都需要进行扩展。
优点:把抽象与实现隔开,有助于独立地管理各组成部分。
缺点:每使用一个桥接元素都要增加一次函数调用,这对程序的性能会有一些负面影响,还提高了系统的复杂程度。
举个栗子:汽车厂商会把同一型号的发动机放到多款车型上使用。拿奥迪为例,假如它有 V6、V8 两款发动机,那么这两款发动机会装载到奥迪轿车或奥迪SUV两种车型中。
// 奥迪轿车(车型一)
class Aodi1 {
constructor(engine) {
this.engine = engine;
}
}
// 轿车平台
Aodi1.prototype.platform = function() {
console.log('aodi1 轿车平台');
}
// 加载轿车发动机
Aodi1.prototype.loadEngine = function() {
this.engine.run();
}
// 奥迪SUV(车型二)
class Aodi2 {
constructor(engine) {
this.engine = engine;
}
}
// SUV平台
Aodi2.prototype.platform = function() {
console.log('aodi2 SUV平台');
}
// 加载SUV发动机
Aodi2.prototype.loadEngine = function() {
this.engine.run();
}
// V6 发动机
function V6() {
this.run = () => {
console.log('v6发动机');
}
}
// V8 发动机
function V8() {
this.run = () => {
console.log('v8发动机');
}
}
// 搭载 V6 发动机的轿车
let car1 = new Aodi1(new V6());
// 搭载 V8 发动机的轿车
let car2 = new Aodi1(new V8());
// 搭载 V8 发动机的SUV
let suv1 = new Aodi2(new V8());
car1.platform();
car1.loadEngine();
car2.platform();
car2.loadEngine();
suv1.platform();
suv1.loadEngine();
组合模式在对象间形成 树形结构;
组合模式中基本对象和组合对象被一致对待;
无须关系对象有多少层,调用时只需在根部进行调用;
比如我们扫描文件夹和文件夹里面的文件,它是一种树形结构,我们从根文件夹出发,扫描二级文件夹,再扫描二级文件夹里的文件…,类似于如下结构:
// 文件夹
const Folder = function(folder) {
this.folder = folder;
this.list = [];
}
// 添加文件夹
Folder.prototype.add = function(res) {
this.list.push(res);
}
// 扫描文件夹
Folder.prototype.scan = function() {
console.log('扫描文件夹', this.folder);
for (let i = 0; i < this.list.length; i++) {
this.list[i].scan();
}
}
// 文件
const File = function(file) {
this.file = file;
}
// 扫描文件
File.prototype.scan = function() {
console.log('开始扫描文件', this.file);
}
// 根文件夹
let rootFolder = new Folder("root");
// 子文件夹
let htmlFolder = new Folder("html");
let cssFolder = new Folder("css");
let jsFolder = new Folder("js");
// 文件
let html4 = new File("html4");
let html5 = new File("html5");
let css2 = new File("css2");
let css3 = new File("css3");
let es5 = new File("es5");
let es6 = new File("es6");
// 添加文件夹
rootFolder.add(htmlFolder);
rootFolder.add(cssFolder);
rootFolder.add(jsFolder);
// 添加文件
htmlFolder.add(html4);
htmlFolder.add(html5);
cssFolder.add(css2);
cssFolder.add(css3);
jsFolder.add(es5);
jsFolder.add(es6);
// 从根扫描
rootFolder.scan();
本文我们了解了发布订阅模式、桥接模式、组合模式。
发布订阅模式 的发布者和订阅者不用相互知道,通过第三方实现调度,属于经过解耦合的观察者模式。
桥接模式是一种 结构型设计模式,用于把抽象化与实现化解耦,使得二者可以独立变化。
组合模式 又叫部分整体模式,是一种 结构型设计模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!
参考资料:
- 百度百科 · 软件设计模式(设计模式)
- 菜鸟教程 · 设计模式
- JavaScript设计模式 【作者:千锋教育】