文档(前端): 设计模式
This commit is contained in:
parent
7014364e28
commit
bf66328cd7
@ -15,31 +15,115 @@ group:
|
||||
|
||||
将一个类的接口转化为另外一个接口,以满足用户需求,使类之间接口不兼容问题通过适配器得以解决。
|
||||
|
||||
案例:新来的大卫封装了个 **fetch** 请求库,但是公司以前的网络请求方法是基于 **XMLHttpRequest** 的,老板想大卫去改这已经写好的9999个接口的请求,大卫使用了适配器模式去兼容,如下:
|
||||
|
||||
```js
|
||||
import react from 'react';
|
||||
// RequestUtil 请求库
|
||||
export default class RequestUtil {
|
||||
// get 方法
|
||||
static get(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url)
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
resolve(result)
|
||||
})
|
||||
.catch(err => reject(err))
|
||||
})
|
||||
}
|
||||
|
||||
class Adapter {
|
||||
constructor(config) {
|
||||
if (!config || typeof config === 'object') {
|
||||
return this.reLoad(config)
|
||||
} else {
|
||||
throw new Error('传递的参数必须为一个对象!')
|
||||
}
|
||||
// post 方法
|
||||
static post(url, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: data
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => resolve(result))
|
||||
.catch(err => reject(err))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 调用
|
||||
const postResp = await RequestUtils.post('https://nicecoders.github.io', data)
|
||||
|
||||
// 公司老的库
|
||||
function Ajax(type, url, data, success, failed){
|
||||
// 创建ajax对象
|
||||
var xhr = null;
|
||||
if(window.XMLHttpRequest){
|
||||
xhr = new XMLHttpRequest();
|
||||
} else {
|
||||
xhr = new ActiveXObject('Microsoft.XMLHTTP')
|
||||
}
|
||||
|
||||
reLoad(arr) {
|
||||
let newObj = {}
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const item = arr[i]
|
||||
newObj[item.name] = item.age
|
||||
|
||||
...(此处省略一系列的业务逻辑细节)
|
||||
|
||||
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 头。
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
// 发送post请求
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// 处理返回数据
|
||||
xhr.onreadystatechange = function(){
|
||||
if(xhr.readyState == 4){
|
||||
if(xhr.status == 200){
|
||||
success(xhr.responseText);
|
||||
} else {
|
||||
if(failed){
|
||||
failed(xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
}
|
||||
|
||||
let aer = new Adapter([{name: 'david', age: 2}])
|
||||
// => {david: 2}
|
||||
// 创建适配器函数,入参与旧接口保持一致
|
||||
async function AjaxAdapter(type, url, data, success, failed) {
|
||||
const type = type.toUpperCase()
|
||||
let result
|
||||
try {
|
||||
// 实际的请求全部由新接口发起
|
||||
if(type === 'GET') {
|
||||
result = await HttpUtils.get(url) || {}
|
||||
} else if(type === 'POST') {
|
||||
result = await HttpUtils.post(url, data) || {}
|
||||
}
|
||||
// 假设请求成功对应的状态码是1
|
||||
result.statusCode === 1 && success ? success(result) : failed(result.statusCode)
|
||||
} catch(error) {
|
||||
// 捕捉网络错误
|
||||
if(failed){
|
||||
failed(error.statusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容了老的调用方式
|
||||
Ajax('get', 'https://nicecoders.github.io', data, function(res){
|
||||
// 成功的回调逻辑
|
||||
}, function(error){
|
||||
// 失败的回调逻辑
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### 装饰器模式
|
||||
@ -52,6 +136,7 @@ let aer = new Adapter([{name: 'david', age: 2}])
|
||||
|
||||
```jsx
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
import '@nicecode/css'
|
||||
|
||||
class Modal {
|
||||
constructor(opt = {}) {
|
||||
@ -120,72 +205,178 @@ export default () => {
|
||||
normalModal()
|
||||
}, [])
|
||||
|
||||
let style = {
|
||||
margin: '0 6px',
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="decorator">
|
||||
<button onClick={openModal} >打开弹框</button>
|
||||
<button onClick={hideModal} >关闭弹框</button>
|
||||
<button onClick={decoratorModal} >添加适配器</button>
|
||||
<button onClick={normalModal} >清除适配器</button>
|
||||
<button style={style} onClick={openModal} >打开弹框</button>
|
||||
<button style={style} onClick={hideModal} >关闭弹框</button>
|
||||
<button style={style} onClick={decoratorModal} >添加适配器</button>
|
||||
<button style={style} onClick={normalModal} >清除适配器</button>
|
||||
<div ref={modalRef} style={{ display: 'none', marginTop: '20px', padding: '10px 20px', border: '1px solid #eee'}} ></div>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
```
|
||||
|
||||
#### 进阶版
|
||||
|
||||
```jsx
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
function funcDecorator(type) {
|
||||
return function (target, name, descriptor) {
|
||||
if (type === 'class') {
|
||||
target.prototype.show = () => {
|
||||
console.log('装饰器处理后的类')
|
||||
}
|
||||
return target
|
||||
/**
|
||||
* or
|
||||
* return class NButton {
|
||||
* show() {
|
||||
* console.log('装饰器处理后')
|
||||
* }
|
||||
* }
|
||||
**/
|
||||
} else if (type === 'function') {
|
||||
const old = descriptor.value
|
||||
descriptor.value = function(...arg) { // 注意这里需要保留原this作用域,不能使用箭头函数
|
||||
console.log('----装饰器装饰函数----')
|
||||
// 原函数
|
||||
return old.apply(this, arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通过装饰器改变原有的 show 方法
|
||||
// @funcDecorator('class')
|
||||
class Button {
|
||||
show() {
|
||||
console.log('大卫的思想空间')
|
||||
}
|
||||
|
||||
@funcDecorator('function')
|
||||
mb() {
|
||||
console.log('我是sb')
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
useEffect(() => {
|
||||
let dom = new Button();
|
||||
// dom.show()
|
||||
// dom.mb()
|
||||
// console.log(dom)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
进阶案例:控制台查看输出结果
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 代理模式
|
||||
### 代理模式
|
||||
|
||||
是为一个对象提供一个代用品或占位符,以便控制对它的访问
|
||||
|
||||
### ES5 版
|
||||
#### 简单版
|
||||
|
||||
```js
|
||||
/**
|
||||
* 代理模式
|
||||
*/
|
||||
export default class ProxyPro {
|
||||
constructor(args) {
|
||||
return new Proxy(args, {
|
||||
get: function (target, key, receiver) {
|
||||
// console.log(target, key, receiver);
|
||||
console.log(`获取 ${key}`)
|
||||
return Reflect.get(target, key, receiver)
|
||||
},
|
||||
set: function (target, key, value, reciver) {
|
||||
console.log(`设置 ${key} 为 ${value}`)
|
||||
return Reflect.set(target, key, value, reciver)
|
||||
}
|
||||
})
|
||||
```jsx
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
|
||||
// 普通私密信息
|
||||
const baseInfo = ['name', 'age', 'career']
|
||||
// 最私密信息
|
||||
const privateInfo = ['avatar', 'phone']
|
||||
|
||||
// 规定礼物的数据结构由type和value组成
|
||||
const present = {
|
||||
type: '巧克力',
|
||||
value: 60,
|
||||
}
|
||||
|
||||
// 相亲男方
|
||||
const user = {
|
||||
isValidated: true,
|
||||
isVIP: false,
|
||||
}
|
||||
|
||||
// 相亲女方
|
||||
const girl = {
|
||||
// 姓名
|
||||
name: '小美',
|
||||
// 自我介绍
|
||||
aboutMe: '...',
|
||||
// 年龄
|
||||
age: 24,
|
||||
// 职业
|
||||
career: 'teacher',
|
||||
// 假头像
|
||||
fakeAvatar: 'xxxx',
|
||||
// 真实头像
|
||||
avatar: 'xxxx',
|
||||
// 手机号
|
||||
phone: 123456,
|
||||
// 礼物数组
|
||||
presents: [],
|
||||
// 拒收50块以下的礼物
|
||||
bottomValue: 50,
|
||||
// 记录最近一次收到的礼物
|
||||
lastPresent: present,
|
||||
}
|
||||
|
||||
// 掘金婚介所推出了小礼物功能
|
||||
const JuejinLovers = new Proxy(girl, {
|
||||
get: function(girl, key) {
|
||||
|
||||
if((baseInfo.indexOf(key) !== -1) && !user.isValidated) {
|
||||
alert('您还没有完成验证哦')
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### ES5 版
|
||||
// 此处我们认为只有验证过的用户才可以购买VIP
|
||||
if(user.isValidated && privateInfo.indexOf(key) !== -1 && !user.isVIP) {
|
||||
alert('只有VIP才可以查看该信息哦')
|
||||
return
|
||||
}
|
||||
|
||||
```js
|
||||
let Flower = function() {}
|
||||
let xiaoming = {
|
||||
sendFlower: function(target) {
|
||||
let flower = new Flower()
|
||||
target.receiveFlower(flower)
|
||||
}
|
||||
}
|
||||
let B = {
|
||||
receiveFlower: function(flower) {
|
||||
A.listenGoodMood(function() {
|
||||
A.receiveFlower(flower)
|
||||
})
|
||||
}
|
||||
}
|
||||
let A = {
|
||||
receiveFlower: function(flower) {
|
||||
console.log('收到花'+ flower)
|
||||
return girl[key]
|
||||
},
|
||||
listenGoodMood: function(fn) {
|
||||
setTimeout(function() {
|
||||
fn()
|
||||
}, 1000)
|
||||
set: function(girl, key, val) {
|
||||
|
||||
// 最近一次送来的礼物会尝试赋值给lastPresent字段
|
||||
// 需要返回 boolean 判断是否赋值成功
|
||||
if(key === 'lastPresent') {
|
||||
if(val.value < girl.bottomValue) {
|
||||
alert('sorry,您的礼物被拒收了')
|
||||
return false
|
||||
}
|
||||
|
||||
// 如果没有拒收,则赋值成功,同时并入presents数组
|
||||
girl.lastPresent = val
|
||||
girl.presents = [...girl.presents, val]
|
||||
return true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default () => {
|
||||
|
||||
useEffect(() => {
|
||||
console.log(JuejinLovers.name)
|
||||
JuejinLovers.lastPresent = present
|
||||
console.log(JuejinLovers)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>hi</div>
|
||||
)
|
||||
}
|
||||
xiaoming.sendFlower(B)
|
||||
```
|
||||
|
@ -13,7 +13,7 @@
|
||||
"test": "umi-test",
|
||||
"test:coverage": "umi-test --coverage",
|
||||
"cz": "git add . && git cz",
|
||||
"log": "conventional-changelog -n ./packages/changelog/src -i changelog.md -s -r 0"
|
||||
"log": "conventional-changelog -n node_modules/@nicecode/changelog -i CHANGELOG.md -s -r 0"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.esm.js",
|
||||
@ -26,7 +26,7 @@
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./packages/commit"
|
||||
"path": "@nicecode/commit"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
@ -38,6 +38,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@nicecode/css": "^0.0.8",
|
||||
"react": "^16.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
Loading…
Reference in New Issue
Block a user