通过例子持续学习JS设计模式中,接下来请跟随我的步伐走进我的学习笔记世界~
什么是设计模式
?我们为什么需要学习设计模式?
设计模式是可以更好解决问题的一种方案。
这意味着什么?如果你开发的项目的功能是固定的,永远不会调整业务,那么你就不需要使用设计模式等任何技巧。您只需要使用通常的方式编写代码并完成需求即可。
但是,我们的开发项目的需求是不断变化的,这就需要我们经常修改我们的代码。也就是说,我们现在写代码的时候,需要为未来业务需求可能发生的变化做好准备。
这时,你会发现使用设计模式可以让你的代码更具可扩展性。
1 命令模式
-
我的理解:
定义一个类,里面写方法,用的时候引入这个类,调用类.方法()使用。 -
定义:
有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁。此时希望用一种松耦合
的方式来设计程序,使得请求发送者
和请求接收者
能够消除彼此之间的耦合关系。
-
适用场景:绘制按钮,不知道某个按钮未来将用来做什么,可能用来刷新菜单界面,也可能用来增加一些子菜单,只知道点击这个按钮会发生某些事情。那么当完成这个按钮的绘制之后,应该如何给它绑定onclick 事件呢? 我们很快可以找到在这里运用命令模式的理由:点击了按钮之后,必须向某些负责具体行为的对象发送请求,这些对象就是请求的接收者。但是目前并不知道接收者是什么对象,也不知道接收者究竟会做什么。此时我们需要借助命令对象的帮助,以便解开按钮和负责具体行为对象之间的耦合。
const btn1 = function () {};
const btn2 = function () {};
// 定义一个命令发布者的类
class Executor {
setCommand(btn, command) {
btn.onclick = function() {
command.execute()
}
}
}
// 定义一个命令接收者
class Menu {
refresh() {
console.log('刷新菜单')
}
addSubMenu() {
console.log('增加子菜单')
}
}
// 定义一个刷新菜单的命令对象的类
class RefreshMenu {
constructor(receiver) {
// 命令对象与接收者关联
this.receiver = receiver
}
// 暴露出统一的接口给命令发布者Executor
execute() {
this.receiver.refresh()
}
}
// 定义一个增加子菜单的命令对象的类
class AddSubMenu {
constructor(receiver) {
// 命令对象与接收者关联
this.receiver = receiver
}
// 暴露出统一的接口给命令发布者Executor
execute() {
this.receiver.addSubMenu()
}
}
var menu = new Menu()
var executor = new Executor()
var refreshMenu = new RefreshMenu(menu)
// 给按钮1添加刷新功能
executor.setCommand(btn1, refreshMenu)
var addSubMenu = new AddSubMenu(menu)
// 给按钮2添加增加子菜单功能
executor.setCommand(btn2, addSubMenu)
// 如果想给按钮3增加删除菜单的功能,就继续增加删除菜单的命令对象和接收者的具体删除方法,而不必修改命令对象
btn1.onclick();
btn2.onclick();
2 单例模式
- 定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。 - 适用场景:
一个单一对象。比如:弹窗,无论点击多少次,弹窗只应该被创建一次。
class CreateUser {
constructor(name) {
this.name = name;
this.getName();
}
getName() {
return this.name;
}
}
// 代理实现单例模式
var ProxyMode = (function() {
var instance = null;
return function(name) {
if(!instance) {
instance = new CreateUser(name);
}
return instance;
}
})();
// 测试单体模式的实例
var a = new ProxyMode("aaa");
var b = new ProxyMode("bbb");
// 因为单体模式是只实例化一次,所以下面的实例是相等的
console.log(a === b); //true
3 策略模式
- 定义:
定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。
策略模式的目的就是将算法的使用和算法的实现分离开来。 - 适用场景
如果您的函数具有以下特征:判断条件很多;各个判断条件下的代码相互独立。然后,你可以将每个判断条件下的代码封装成一个独立的函数,接着,建立判断条件和具体策略的映射关系,使用策略模式重构你的代码。
/** 假设您目前正在从事一个电子商务商店的项目。
* 每个产品都有一个原价,我们可以称之为 originalPrice。
* 但并非所有产品都以原价出售,我们可能会推出允许以折扣价
* 出售商品的促销活动。商家可以在后台为产品设置不同的状态。
* 然后实际售价将根据产品状态和原价动态调整。
* 具体规则:xxxxxxxxx;
* 如果你需要写一个getPrice函数,你应该怎么写呢?*/
let priceStrategies = {
'pre-sale': preSalePrice,
'promotion': promotionPrice,
'black-friday': blackFridayPrice,
'default': defaultPrice
}
function getPrice(originalPrice, status) {
return priceStrategies[status](originalPrice)
}
function blackFridayPrice(origialPrice) {
if (origialPrice >= 100 && originalPrice < 200) {
return origialPrice - 20
} else if (originalPrice >= 200) {
return originalPrice - 50
} else {
return originalPrice * 0.8
}
}
function defaultPrice(origialPrice) {
return origialPrice
}
function getPrice(originalPrice, status) {
if (status === 'pre-sale') {
return preSalePrice(originalPrice)
}
if (status === 'promotion') {
return promotionPrice(originalPrice)
}
if (status === 'black-friday') {
return blackFridayPrice(originalPrice)
}
if(status === 'default'){
return defaultPrice(originalPrice)
}
}