js设计模式思想与实现

这里写目录标题

  • 1 创建型模式
    • 1.1 构造器模式 1
    • 1.2 原型模式 2
    • 1.3 工厂模式 3
    • 1.4 抽象工厂模式 4
    • 1.5 建造者模式 5
    • 1.6 单例模式 6
  • 2 结构型模式
    • 2.1 装饰器模式 7
    • 2.2 适配器模式 8
    • 2.3 代理模式 9
    • 2.4 桥接模型 10
    • 2.5 组合模式 11
  • 3 行为(关系)型模式
    • 3.1 观察者模式 12
    • 3.2 发布订阅模式 13
    • 3.3 模块模式 14
    • 3.4 命令模式 15
    • 3.5 模板方法模式 16
    • 3.6 迭代器模型 17
    • 3.7 责任链模式 18
    • 3.8 策略模式 19

1 创建型模式

1.1 构造器模式 1

需要定义对象变量的时候使用,避免反复的定义

let animal1 = {name: '猫猫',age: 4
}
let animal2 = {name: '狗狗',age: 5
}
// 以上太麻烦
class Animal {constructor(name, age) {this.name = namethis.age = age}
}
let animal3 = new Animal('鼠鼠', 3)
console.log(animal1, animal2, animal3)

1.2 原型模式 2

  • 正式说明:使用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
  • 我的理解:将对象方法放入到原型链中,避免每次都在创建对象的时候创建相同的方法。
const user = {powers: [],setPowers (power) {this.powers.push(power);},clone () {var newForm = Object.create(this);newForm.powers = Object.create(this.powers);return newForm;}
};
const temp1 = Object.create(user);
const temp2 = temp1.clone();
const temp3 = {powers: [],setPowers (power) {this.powers.push(power);},clone () {var newForm = Object.create(this);newForm.powers = Object.create(this.powers);return newForm;}
};

1.3 工厂模式 3

  • 正式定义:定义一个用于创建对象的类/函数,让其决定将哪一个类/函数实例化
  • 我的理解:根据参数的不同创建不同的对象,避免需要的输入很多数据
class User {constructor(role, power) {this.role = rolethis.power = power}
}
let user1 = new User('admin', ['home', 'mine', 'about', 'manage'])
let user2 = new User('member', ['home', 'mine', 'about'])
let user3 = new User('assistant', ['home', 'finance', 'inventory'])
// 以上太麻烦
class Userc {constructor(role, power) {this.role = rolethis.power = power}static GenerateUser (role, power) {switch (role) {case 'admin':return new Userc('admin', ['home', 'mine', 'about', 'manage'])break;case 'member':return new Userc('member', ['home', 'mine', 'about'])break;case 'assistant':return new Userc('assistant', ['home', 'finance', 'inventory'])break;default:return new Userc(role, power)break}}
}
let user4 = Userc.GenerateUser('admin')
let user5 = Userc.GenerateUser('member')
let user6 = Userc.GenerateUser('assistant')
console.log(user1, user3)

1.4 抽象工厂模式 4

  • 正式说明:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
  • 我的理解:工厂模式的升级版。如果工厂模式的用户角色多了起来,或者他们还有不同的功能,就会导致User类中的代码量很多,并且可能造成冗余,所以需要创建抽象类定义通用功能,再通过函数创建对应的工厂。
// 抽象类
class User {constructor(role, power) {this.role = rolethis.power = power}pushData () {console.log('推送数据')}static GenerateUser (role, power) {switch (role) {case 'admin':return new Admin()break;case 'member':return new Member()break;case 'assistant':return new Assistant()break;default:return new User(role, power)break}}
}
class Admin extends User {constructor(role, power) {super('admin', ['home', 'mine', 'about', 'manage'])}banUser () {console.log('封禁用户')}
}
class Member extends User {constructor(role, power) {super('member', ['home', 'mine', 'about'])}
}
class Assistant extends User {constructor(role, power) {super('assistant', ['home', 'finance', 'inventory'])}handle () {console.log('辅助处理数据')}
}let user1 = User.GenerateUser('admin')
let user2 = User.GenerateUser('member')
let user3 = User.GenerateUser('assistant')
console.log(user1, user3)

1.5 建造者模式 5

  • 正式说明:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  • 我的理解:通过一个类来执行,不同类方法的一个过程
class Yagu {constructor() {this.name = "亚古兽"this.level = 1}first () {this.name = '暴龙兽'this.level++console.log('进化了', this.name, this.level)}second () {this.name = '机械暴龙兽'this.level++console.log('进化了', this.name, this.level)}third () {this.name = '战斗暴龙兽'this.level++console.log('进化了', this.name, this.level)}
}
class Jiabu {constructor() {this.name = "加布兽"this.level = 1}first () {this.name = '加鲁鲁兽'this.level++console.log('进化了', this.name, this.level)}second () {this.name = '兽人加鲁鲁'this.level++console.log('进化了', this.name, this.level)}third () {this.name = '机械加鲁鲁'this.level++console.log('进化了', this.name, this.level)}
}
class Evolution {start (digitalMonster) {digitalMonster.first()digitalMonster.second()digitalMonster.third()}
}
const ev = new Evolution()
ev.start(new Yagu())
ev.start(new Jiabu())

1.6 单例模式 6

  • 正式说明:保证一个类仅有一个实例
class Singleton {constructor(name) {if (Singleton.instance) {return Singleton.instance}else {this.name = nameSingleton.instance = thisreturn Singleton.instance}}
}
console.log(new Singleton('张三'), new Singleton('李四'), new Singleton('张三') === new Singleton('李四'))

2 结构型模式

2.1 装饰器模式 7

  • 正式说明:动态地给一个对象添加一些额外的职责。就扩展功能而言, 它比生成子类方式更为灵活。
  • 我的理解:在不修改类/对象/函数原有功能的基础上增加新的功能。
class User {role = "admin"power = ['home', 'mine', 'about', 'manage']constructor(userName) {this.userName = userName}login () {console.log('login')return this.power}
}
// 不修改原有的类,在实例方法login前后各增加一个函数,并形成行的函数
User.decoration = function (instance) {instance.before = function () {console.log('before')}instance.after = function () {console.log('after')}instance.loginC = function () {this.before()let result = this.login()this.after()return result}
}
let user = new User()
User.decoration(user)
console.log(user.loginC())

2.2 适配器模式 8

  • 正式说明:将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 我的理解:对类进行二次封装,使其他方法更方便的调用。
class WxPlay {constructor() {}pay () {console.log('调用微信支付')}
}
class AliPlay {constructor() {}alipayPay () {console.log('调用支付宝支付')}
}
// 现有两个支付类,需要通过判断调用,但是由于支付方法不同,调用统一方法,所以进行二次封装,使方法名统一
class AliPlayHandle extends AliPlay {constructor() {super()}pay () {this.alipayPay()}
}
class Pay {constructor(wx, ali) {this.wx = wxthis.ali = ali}pay (way) {this[way].pay()}
}
const wx = new WxPlay()
const ali = new AliPlayHandle()
const pay = new Pay(wx, ali)
pay.pay('wx')
pay.pay('ali')

2.3 代理模式 9

  • 正式说明:在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口
  • 我的理解:通过一个类作为中转,操作另一个类
class PiggyBank {constructor() {this.money = 0}deposit(money) {this.money += money}withdraw() {return this.money}clear() {this.money = 0}
}
class Agent {constructor() {this.piggyBank = new PiggyBank()}set(num) {this.piggyBank.deposit(num)}get() {let temp = this.piggyBank.withdraw()this.piggyBank.clear()return temp}
}
const agent = new Agent()
agent.set(10)
agent.set(10)
agent.set(10)
console.log(agent.get(), agent)

2.4 桥接模型 10

  • 正式说明:桥接模式把抽象层次结构从实现中分离出来,使其能够独立变更。抽象层定义了供客户端使用的上层抽象接口。实现层次结构定义了供抽象层次使用的底层接口。
  • 我的理解:使抽象类和实现类各自独立,但是还可以通过抽象类实例调用实现类的方法。
// 抽象类
class User {constructor(instance) {this.instance = instance}login () {this.instance.login()}getPower () {this.instance.getPower()}
}
// 实现类
class Admin {login () {console.log('管理员登录')}getPower () {console.log('管理员获取权限')}
}
// 实现类
class Member {login () {console.log('用户登录')}getPower () {console.log('用户获取权限')}
}
const admin = new User(new Admin())
const member = new User(new Member())
admin.login()
admin.getPower()
member.login()
member.getPower()

2.5 组合模式 11

  • 正式说明:它允许将对象组合成树形结构,并且可以像操作单个对象一样操作整个树形结构。
  • 我的理解:让一些类有同样的方法和属性,并让它们组成树形结构,并且可以通过调用根节点的方法,对整体进行操作。
// 规范支和叶的行为
class Element {constructor(name) {this.name = namethis.list = []}insert () {throw new Error('没有重写insert方法')}output () {throw new Error('没有重写output方法')}getNamePosition () {throw new Error('没有重写getNamePosition方法')}
}
// 定义树枝
class Branch extends Element {constructor(name) {super(name)}insert (ele) {this.list.push(ele)return this}output () {console.log(this.name)this.list.forEach(item => {item.output()});}getNamePosition (name, index = undefined) {for (let i = 0; i < this.list.length; i++) {const ele = this.list[i];const temp = ele.getNamePosition(name, `${index ? index + '-' : ''}${i}`)if (temp) return temp}if (name === this.name) return indexreturn false}
}
// 定义树
class Leaf extends Element {constructor(name) {super(name)}output () {console.log(this.name)}getNamePosition (name, index = 0) {if (name === this.name) return indexreturn false}
}
const root = new Branch('根')
const branch1 = new Branch('一级枝干1')
const branch2 = new Branch('一级枝干2')
const branch11 = new Branch('二级枝干11')
const branch12 = new Branch('二级枝干12')
const leaf1 = new Leaf('树叶1')
const leaf2 = new Leaf('树叶2')
const leaf3 = new Leaf('树叶3')
root.insert(branch1).insert(branch2)
branch1.insert(branch11).insert(branch12)
branch11.insert(leaf1)
branch12.insert(leaf2)
branch2.insert(leaf3)
root.output()
console.log(root.getNamePosition('树叶2'))
console.log(root.getNamePosition('树叶3'))
console.log(root)
leaf3.insert()

3 行为(关系)型模式

3.1 观察者模式 12

  • 正式说明:观察者(Observer) 模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
  • 我的理解:当一个类做出改变可以通知另外一个类做出对应的处理。
class Mouth {constructor() {this.observes = []}addObserve(observe) {this.observes.push(observe)return this}eat() {console.log('吃吃吃')this.observes.forEach(item => {item.func()})}
}
class Organ {constructor(name, func) {this.name = namethis.func = func}
}
const mouth = new Mouth()
const organ1 = new Organ('胃', () => console.log('分泌胃酸'))
const organ2 = new Organ('胆', () => console.log('分泌胆汁'))
const organ3 = new Organ('胰腺', () => console.log('分泌胰岛素'))
mouth.addObserve(organ1).addObserve(organ2).addObserve(organ3)
mouth.eat()

3.2 发布订阅模式 13

  • 正式说明:也叫消息队列模式,它是一种将发布者和订阅者解耦的设计模式。在前端开发中,可以使用发布-订阅模式来实现组件之间的通信。
  • 我的理解:观察者模式的升级版,在A直接通知C的中间加一层中转者B,使功能解耦。
class PubSub {constructor() {this.message = {}}publisg(key, callback) {this.message[key].push(callback)return this}remove(key, callback) {const element = this.message[key]for (let i = 0; i < element; i++) {if (callback === element[i]) {this.message[key].splice(i, 1)break}}}subscribe(key, data) {this.message[key].forEach(item => {item()})}
}

3.3 模块模式 14

const a = (function () {var b = 0return {add() {return ++b},reduce() {return --b		}}
})()
console.log(a)

3.4 命令模式 15

  • 正式说明:命令模式将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能。
  • 我的理解:感觉跟代理模式很像,让A和C互不影响,专注自己的事情,通过增加B,使A和C产生关联。
// 抽象命令类
class Command {execute() {throw new Error('该方法必须重写')}
}
// 接收者类
class Receiver {action() {console.log('执行请求')}
}
// 具体命令类
class ConcreteCommand extends Command {constructor(receiver) {super()this.receiver = receiver}execute() {this.receiver.action()}
}
// 发送者类
class Invoker {constructor(command) {this.command = command}setCommand(command) {this.command = command}executeCommand() {this.command.execute()}
}
// 使用示例
const receiver = new Receiver()
const concreteCommand = new ConcreteCommand(receiver)
const invoker = new Invoker(concreteCommand)
// 发送请求
invoker.executeCommand()

3.5 模板方法模式 16

  • 正式说明:定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。
  • 我的理解:父类中定义具体的方法和方法的执行过程,子类可以根据不同的需求来重写方法。
// 可以以计算商品的价格举例
class Process {constructor(count, price) {this.count = countthis.price = price}calculate () {this.basicPrice = this.count * this.pricethis.preferential()this.freight()if (this.basicPrice < 0) this.basicPrice = 0console.log(this.basicPrice)}freight () {this.basicPrice += 5}preferential () {this.basicPrice -= 1}
}
// 满减
class FullReduction extends Process {constructor(count, price) {super(count, price)}freight () {if (this.basicPrice > 49) {this.basicPrice += 3}else {this.basicPrice += 0}}preferential () {if (this.basicPrice > 200) {this.basicPrice -= 20}if (this.basicPrice > 500) {this.basicPrice -= 60}}
}
class GroupBuy extends Process {constructor(count, price) {super(count, price)}freight () {this.basicPrice += 5}preferential () {const discount = 1 - this.count * 0.001this.basicPrice *= discount > 0.8 ? discount : 0.8this.basicPrice = Math.round(this.basicPrice)}
}
new FullReduction(3, 10).calculate()
new FullReduction(4, 10).calculate()
new FullReduction(5, 10).calculate()
new FullReduction(21, 10).calculate()
new FullReduction(49, 10).calculate()
new FullReduction(51, 10).calculate()
new GroupBuy(3, 10).calculate()
new GroupBuy(4, 10).calculate()
new GroupBuy(5, 10).calculate()
new GroupBuy(21, 10).calculate()
new GroupBuy(49, 10).calculate()
new GroupBuy(51, 10).calculate()

3.6 迭代器模型 17

  • 正式说明:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示
  • 我的理解:JS中的forEach
function myForEach (array, callback) {for (let index = 0; index < array.length; index++) {const item = array[index];callback(item, index)}
}
function myMap (array, callback) {let load = []for (let index = 0; index < array.length; index++) {const item = array[index];load.push(callback(item, index))}return load
}
const array = [123, 'abc', null, [4, 5, 6], undefined, { d: 'e' }]
myForEach(array, (item, index) => {console.log(item, index)
})
const newArray = myMap(array, (item, index) => {return index
})
console.log(newArray)

3.7 责任链模式 18

  • 正式说明:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
  • 我的理解:类似于原型链,是一个链表的调用。
class Chain {constructor(fn) {this.fn = fnthis.next = null}addChain (fn) {this.next = fnreturn this}check (value) {this.fn(value) ? this.next.check(value) : null}
}
function CheckNull (value) {if (!value) {console.log('值不能为空')return false}return true
}
function checkNumber (value) {if (!isNaN(+value)) {console.log('必须为数值类型')return false}return true
}
function checkPhone (value) {const ret = /^1((34[0-8])|(8\d{2})|(([35][0-35-9]|4[579]|66|7[35678]|9[1389])\d{1}))\d{7}$/if (!ret.test(value)) {console.log('手机号格式不正确')return false}return true
}
new Chain(CheckNull).addChain(new Chain(checkNumber).addChain(new Chain(checkPhone))).check('')

3.8 策略模式 19

  • 正式说明:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
  • 我的理解:在程序运行的时候动态地指定要使用的算法。
const strategies = {"S": function (salary) {return salary * 4},"A": function (salary) {return salary * 3},"B": function (salary) {return salary * 2}
}
function calculateBonus (level, salary) {return strategies[level](salary)
}

持续更新……
可以看看这个,写的还挺好

本文链接:https://my.lmcjl.com/post/1943.html

展开阅读全文

4 评论

留下您的评论.