fix: 修改设计模式

This commit is contained in:
haishan 2021-09-30 02:02:15 +08:00
parent bf66328cd7
commit 6f5630dfd8
2 changed files with 258 additions and 70 deletions

View File

@ -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>
```

View File

@ -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