fix: 修改设计模式
This commit is contained in:
parent
bf66328cd7
commit
6f5630dfd8
@ -9,15 +9,81 @@ group:
|
||||
|
||||
## 行为型
|
||||
|
||||
### 发布订阅者模式
|
||||
### 状态模式
|
||||
|
||||
#### 状态模式
|
||||
|
||||
场景:
|
||||
|
||||
一台咖啡机,按需求给不同的咖啡:
|
||||
- 美式咖啡态(american):只吐黑咖啡
|
||||
- 普通拿铁态(latte):黑咖啡加点奶
|
||||
- 香草拿铁态(vanillaLatte):黑咖啡加点奶再加香草糖浆
|
||||
- 摩卡咖啡态(mocha):黑咖啡加点奶再加点巧克力
|
||||
|
||||
```js
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
class CoffeeMachine {
|
||||
constructor() {
|
||||
this.state = 'init'
|
||||
this.leftMilk = '500ml'
|
||||
}
|
||||
|
||||
// 美式
|
||||
american() {
|
||||
// 尝试在行为函数里拿到咖啡机实例的信息并输出
|
||||
console.log('咖啡机现在的牛奶存储量是:', this.leftMilk)
|
||||
console.log('我只吐黑咖啡');
|
||||
return '美式'
|
||||
}
|
||||
|
||||
// 普通拿铁
|
||||
latte() {
|
||||
this.american()
|
||||
console.log('加点奶');
|
||||
return '普通拿铁'
|
||||
}
|
||||
|
||||
// 香草拿铁
|
||||
vanillaLatte() {
|
||||
this.latte();
|
||||
console.log('再加香草糖浆');
|
||||
return '香草拿铁'
|
||||
}
|
||||
|
||||
// 摩卡
|
||||
mocha() {
|
||||
this.latte();
|
||||
console.log('再加巧克力');
|
||||
return '摩卡'
|
||||
}
|
||||
|
||||
changeState(state) {
|
||||
this.state = state;
|
||||
if (!this[state]) {
|
||||
return
|
||||
}
|
||||
return this[state]()
|
||||
}
|
||||
}
|
||||
|
||||
const mk = new CoffeeMachine()
|
||||
|
||||
|
||||
export default () => <div>咖啡类型:{mk.changeState('mocha')}</div>
|
||||
```
|
||||
|
||||
### 观察者模式(发布订阅者模式)
|
||||
|
||||
定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使它们能够自动更新自己,当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。
|
||||
|
||||
#### 简单版
|
||||
|
||||
```js
|
||||
```jsx
|
||||
import React from 'react';
|
||||
// 主题 保存状态,状态变化之后触发所有观察者对象
|
||||
class Subject {
|
||||
class Publisher {
|
||||
constructor() {
|
||||
this.state = 0
|
||||
this.observers = []
|
||||
@ -41,93 +107,215 @@ class Subject {
|
||||
|
||||
// 观察者
|
||||
class Observer {
|
||||
constructor(name, subject) {
|
||||
constructor(name, publisher) {
|
||||
this.name = name
|
||||
this.subject = subject
|
||||
this.subject.attach(this)
|
||||
this.publisher = publisher
|
||||
this.publisher.attach(this)
|
||||
}
|
||||
update() {
|
||||
console.log(`${this.name} update, state: ${this.subject.getState()}`)
|
||||
console.log(`${this.name} 更新, state: ${this.publisher.getState()}`)
|
||||
}
|
||||
}
|
||||
|
||||
// 测试
|
||||
let s = new Subject()
|
||||
let o1 = new Observer('o1', s)
|
||||
let o2 = new Observer('02', s)
|
||||
let pub = new Publisher()
|
||||
let o1 = new Observer('o1', pub)
|
||||
let o2 = new Observer('02', pub)
|
||||
|
||||
s.setState(12)
|
||||
pub.setState(12)
|
||||
|
||||
export default () => null
|
||||
```
|
||||
|
||||
#### 复杂版
|
||||
|
||||
```js
|
||||
/**
|
||||
* 发布订阅者模式
|
||||
*/
|
||||
export default class EventEmitter {
|
||||
constructor() {
|
||||
this.subs = {}
|
||||
}
|
||||
// 定义发布者
|
||||
class Publisher {
|
||||
constructor() {
|
||||
this.observers = []
|
||||
console.log('发布者创建-执行')
|
||||
}
|
||||
|
||||
on(event, cb) {
|
||||
(this.subs[event] || (this.subs[event] = [])).push(cb)
|
||||
}
|
||||
// 增加订阅者
|
||||
add(observer) {
|
||||
console.log('增加订阅者-执行')
|
||||
this.observers.push(observer)
|
||||
}
|
||||
|
||||
trigger(event, ...args) {
|
||||
this.subs[event] &&
|
||||
this.subs[event].forEach(cb => {
|
||||
cb(...args)
|
||||
})
|
||||
}
|
||||
|
||||
once(event, onceCb) {
|
||||
const cb = (...args) => {
|
||||
onceCb(...args)
|
||||
this.off(event, onceCb)
|
||||
}
|
||||
this.on(event, cb)
|
||||
}
|
||||
|
||||
off(event, offCb) {
|
||||
if (this.subs[event]) {
|
||||
let index = this.subs[event].findIndex(cb => cb === offCb)
|
||||
this.subs[event].splice(index, 1)
|
||||
if (!this.subs[event].length) delete this.subs[event]
|
||||
}
|
||||
}
|
||||
// 移除订阅者
|
||||
remove(observer) {
|
||||
console.log('发布者移除-执行')
|
||||
this.observers.forEach((item, i) => {
|
||||
if (item === observer) {
|
||||
this.observers.splice(i, 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 通知所有订阅者
|
||||
notify() {
|
||||
console.log('通知所有订阅者-执行')
|
||||
this.observers.forEach(observer => {
|
||||
observer.update(this)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 定义订阅者类
|
||||
class Observer {
|
||||
constructor() {
|
||||
console.log('订阅者创建-执行')
|
||||
}
|
||||
|
||||
update() {
|
||||
console.log('订阅者被通知了!!')
|
||||
}
|
||||
}
|
||||
|
||||
// 定义一个具体的需求文档发布类
|
||||
class ProPublisher extends Publisher {
|
||||
constructor() {
|
||||
super()
|
||||
// 初始化需求文档
|
||||
this.proState = null
|
||||
this.observers = []
|
||||
console.log('业务订阅者创建-执行')
|
||||
}
|
||||
|
||||
getState() {
|
||||
console.log('业务获取状态-执行')
|
||||
}
|
||||
|
||||
setState(state) {
|
||||
console.log('业务设置状态-执行')
|
||||
this.proState = state
|
||||
this.notify()
|
||||
}
|
||||
}
|
||||
|
||||
// 定义一个监听者
|
||||
class ProObserver extends Observer {
|
||||
constructor() {
|
||||
super()
|
||||
// 需求文档一开始还不存在,prd初始为空对象
|
||||
this.prdState = {}
|
||||
console.log('ProObserver created')
|
||||
}
|
||||
|
||||
// 重写一个具体的update方法
|
||||
update(publisher) {
|
||||
console.log('ProObserver 已执行')
|
||||
// 更新需求文档
|
||||
this.prdState = publisher.getState()
|
||||
// 调用工作函数
|
||||
this.work()
|
||||
}
|
||||
|
||||
// work方法,一个专门搬砖的方法
|
||||
work() {
|
||||
// 获取需求文档
|
||||
const prd = this.prdState
|
||||
// 开始基于需求文档提供的信息搬砖。。。
|
||||
...
|
||||
console.log('996 开始了...')
|
||||
}
|
||||
}
|
||||
|
||||
// 创建订阅者:前端开发C
|
||||
const C = new ProObserver()
|
||||
// 创建订阅者:服务端开发小A
|
||||
const A = new ProObserver()
|
||||
// 创建订阅者:测试同学小B
|
||||
const B = new ProObserver()
|
||||
// 韩梅梅出现了
|
||||
const hanMeiMei = new PrdPublisher()
|
||||
// 需求文档出现了
|
||||
const prd = {
|
||||
// 具体的需求内容
|
||||
...
|
||||
}
|
||||
// 韩梅梅开始拉群
|
||||
hanMeiMei.add(C)
|
||||
hanMeiMei.add(A)
|
||||
hanMeiMei.add(B)
|
||||
// 韩梅梅发送了需求文档,并@了所有人
|
||||
hanMeiMei.setState(prd)
|
||||
```
|
||||
|
||||
### 策略模式
|
||||
|
||||
```js
|
||||
#### 简单版
|
||||
|
||||
业务场景如下:
|
||||
|
||||
马上大促要来了,我们本次大促要做差异化询价。啥是差异化询价?就是说同一个商品,我通过在后台给它设置不同的价格类型,可以让它展示不同的价格。具体的逻辑如下:
|
||||
|
||||
* 当价格类型为“预售价”时,满 100 - 20,不满 100 打 9 折
|
||||
* 当价格类型为“大促价”时,满 100 - 30,不满 100 打 8 折
|
||||
* 当价格类型为“返场价”时,满 200 - 50,不叠加
|
||||
* 当价格类型为“尝鲜价”时,直接打 5 折
|
||||
|
||||
```jsx
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
class CalculateMoney {
|
||||
constructor(type, money) {
|
||||
this.money = money
|
||||
return this.switchStrategy(type, money)
|
||||
// 处理预热价
|
||||
prePrice(originPrice) {
|
||||
if(originPrice >= 100) {
|
||||
return originPrice - 20
|
||||
}
|
||||
return originPrice * 0.9
|
||||
}
|
||||
|
||||
// 处理大促价
|
||||
onSalePrice(originPrice) {
|
||||
if(originPrice >= 100) {
|
||||
return originPrice - 30
|
||||
}
|
||||
return originPrice * 0.8
|
||||
}
|
||||
|
||||
// 处理返场价
|
||||
backPrice(originPrice) {
|
||||
if(originPrice >= 200) {
|
||||
return originPrice - 50
|
||||
}
|
||||
return originPrice
|
||||
}
|
||||
|
||||
// 处理尝鲜价
|
||||
freshPrice(originPrice) {
|
||||
return originPrice * 0.5
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} type 类型
|
||||
* @param {number} money 金额
|
||||
*/
|
||||
switchStrategy(type, money) {
|
||||
let tp = type.toLocaleLowerCase()
|
||||
if (tp === 'a') {
|
||||
return this.money = money * 100
|
||||
} else if (tp === 'b') {
|
||||
return this.money = money * 200
|
||||
} else if (tp === 'c') {
|
||||
return this.money = money * 300
|
||||
} else {
|
||||
return this.money = money * 400
|
||||
}
|
||||
* type: pre 预售 | onSale 大促 | back 返场 | fresh 尝鲜
|
||||
* money: 原始金额
|
||||
**/
|
||||
static get(type, money) {
|
||||
switch (type) {
|
||||
case 'pre':
|
||||
return this.prototype.prePrice(money)
|
||||
break
|
||||
case 'onSale':
|
||||
return this.prototype.onSalePrice(money)
|
||||
break;
|
||||
case 'back':
|
||||
return this.prototype.backPrice(money)
|
||||
break;
|
||||
case 'fresh':
|
||||
return this.prototype.freshPrice(money)
|
||||
break;
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let calculateMoney = new CalculateMoney('', 10000)
|
||||
let calculateMoney = CalculateMoney.get('back', 10000)
|
||||
// => 4000000
|
||||
|
||||
export default () => <div>初始金额:10000,策略模式:{calculateMoney}</div>
|
||||
```
|
||||
|
@ -61,19 +61,19 @@ function Ajax(type, url, data, success, failed){
|
||||
} else {
|
||||
xhr = new ActiveXObject('Microsoft.XMLHTTP')
|
||||
}
|
||||
|
||||
|
||||
...(此处省略一系列的业务逻辑细节)
|
||||
|
||||
|
||||
var type = type.toUpperCase();
|
||||
|
||||
|
||||
// 识别请求类型
|
||||
if(type == 'GET'){
|
||||
if(data){
|
||||
xhr.open('GET', url + '?' + data, true); //如果有数据就拼接
|
||||
}
|
||||
}
|
||||
// 发送get请求
|
||||
xhr.send();
|
||||
|
||||
|
||||
} else if(type == 'POST'){
|
||||
xhr.open('POST', url, true);
|
||||
// 如果需要像 html 表单那样 POST 数据,使用 setRequestHeader() 来添加 http 头。
|
||||
@ -350,7 +350,7 @@ const JuejinLovers = new Proxy(girl, {
|
||||
return girl[key]
|
||||
},
|
||||
set: function(girl, key, val) {
|
||||
|
||||
|
||||
// 最近一次送来的礼物会尝试赋值给lastPresent字段
|
||||
// 需要返回 boolean 判断是否赋值成功
|
||||
if(key === 'lastPresent') {
|
||||
@ -368,7 +368,7 @@ const JuejinLovers = new Proxy(girl, {
|
||||
})
|
||||
|
||||
export default () => {
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
console.log(JuejinLovers.name)
|
||||
JuejinLovers.lastPresent = present
|
||||
|
Loading…
Reference in New Issue
Block a user