修改设计模式
This commit is contained in:
parent
f3f3c12566
commit
7014364e28
64
docs/fea/pattern/about.md
Normal file
64
docs/fea/pattern/about.md
Normal file
@ -0,0 +1,64 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 1
|
||||
---
|
||||
|
||||
## 关于
|
||||
|
||||
## SOLID 设计原则
|
||||
|
||||
|
||||
设计模式需要遵循五个原则,被称为SOLID原则,内容分别是:
|
||||
|
||||
* 单一功能原则(Single Responsibility Principle)
|
||||
* 开放封闭原则(Opened Closed Principle)
|
||||
* 里式替换原则(Liskov Substitution Principle)
|
||||
* 接口隔离原则(Interface Segregation Principle)
|
||||
* 依赖反转原则(Dependency Inversion Principle)
|
||||
|
||||
> "SOLID" 是由罗伯特·C·马丁在 21 世纪早期引入的记忆术首字母缩略字,指代了面向对象编程和面向对象设计的五个基本原则。
|
||||
|
||||
## 设计模式分类(早期22种,新增1种)
|
||||
|
||||
### 创建型
|
||||
|
||||
创建型模式封装了创建对象过程中的变化,它做的事情就是将创建对象的过程抽离;
|
||||
|
||||
* 单例模式
|
||||
* 原型模式
|
||||
* 构造器模式
|
||||
* 工厂模式
|
||||
* 抽象工厂模式
|
||||
* 建造者(新)
|
||||
|
||||
### 结构型
|
||||
|
||||
结构型模式封装的是对象之间组合方式的变化,目的在于灵活地表达对象间的配合与依赖关系;
|
||||
|
||||
* 桥接模式
|
||||
* 外观模式
|
||||
* 组合模式
|
||||
* 装饰器模式
|
||||
* 适配器模式
|
||||
* 代理模式
|
||||
* 享元模式
|
||||
|
||||
### 行为型
|
||||
|
||||
而行为型模式则将是对象千变万化的行为进行抽离,确保我们能够更安全、更方便地对行为进行更改
|
||||
|
||||
* 迭代器模式
|
||||
* 解释器模式
|
||||
* 观察者模式
|
||||
* 中介者模式
|
||||
* 访问者模式
|
||||
* 状态模式
|
||||
* 备忘录模式
|
||||
* 策略模式
|
||||
* 模板方法模式
|
||||
* 职责链模式
|
||||
* 命令模式
|
@ -7,11 +7,13 @@ group:
|
||||
order: 6
|
||||
---
|
||||
|
||||
## 发布订阅者模式
|
||||
## 行为型
|
||||
|
||||
### 发布订阅者模式
|
||||
|
||||
定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使它们能够自动更新自己,当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。
|
||||
|
||||
### 简单版
|
||||
#### 简单版
|
||||
|
||||
```js
|
||||
// 主题 保存状态,状态变化之后触发所有观察者对象
|
||||
@ -57,7 +59,7 @@ let o2 = new Observer('02', s)
|
||||
s.setState(12)
|
||||
```
|
||||
|
||||
### 复杂版
|
||||
#### 复杂版
|
||||
|
||||
```js
|
||||
/**
|
||||
@ -95,4 +97,37 @@ export default class EventEmitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
### 策略模式
|
||||
|
||||
```js
|
||||
class CalculateMoney {
|
||||
constructor(type, money) {
|
||||
this.money = money
|
||||
return this.switchStrategy(type, money)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let calculateMoney = new CalculateMoney('', 10000)
|
||||
// => 4000000
|
||||
```
|
@ -1,39 +0,0 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 4
|
||||
---
|
||||
|
||||
## 适配器模式
|
||||
|
||||
将一个类的接口转化为另外一个接口,以满足用户需求,使类之间接口不兼容问题通过适配器得以解决。
|
||||
|
||||
```js
|
||||
import react from 'react';
|
||||
|
||||
class Adapter {
|
||||
constructor(config) {
|
||||
if (!config || typeof config === 'object') {
|
||||
return this.reLoad(config)
|
||||
} else {
|
||||
throw new Error('传递的参数必须为一个对象!')
|
||||
}
|
||||
}
|
||||
|
||||
reLoad(arr) {
|
||||
let newObj = {}
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const item = arr[i]
|
||||
newObj[item.name] = item.age
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
}
|
||||
|
||||
let aer = new Adapter([{name: 'david', age: 2}])
|
||||
// => {david: 2}
|
||||
```
|
@ -1,51 +0,0 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 3
|
||||
---
|
||||
|
||||
## 建造者模式
|
||||
|
||||
```js
|
||||
// 建造者模式 需要优化
|
||||
export default class Builder {
|
||||
constructor() {
|
||||
this.name = ''
|
||||
this.author = ''
|
||||
this.price = 0
|
||||
this.category = ''
|
||||
}
|
||||
|
||||
withName(name) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
withAuthor(author) {
|
||||
this.author = author
|
||||
return this
|
||||
}
|
||||
|
||||
withPrice(price) {
|
||||
this.price = price
|
||||
return this
|
||||
}
|
||||
|
||||
withCategory(category) {
|
||||
this.category = category
|
||||
return this
|
||||
}
|
||||
|
||||
build() {
|
||||
return {
|
||||
name: this.name,
|
||||
author: this.author,
|
||||
price: this.price,
|
||||
category: this.category
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
301
docs/fea/pattern/createType.md
Normal file
301
docs/fea/pattern/createType.md
Normal file
@ -0,0 +1,301 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 2
|
||||
---
|
||||
|
||||
## 创建型
|
||||
|
||||
创建型模式封装了创建对象过程中的变化,它做的事情就是将创建对象的过程抽离;
|
||||
|
||||
### 工厂模式
|
||||
|
||||
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。
|
||||
|
||||
#### 简单版
|
||||
|
||||
场景是我需要创建500个用户,他们分别有不同的角色,页面访问不同权限。
|
||||
|
||||
```js
|
||||
class User {
|
||||
constructor(name, type, viewPage) {
|
||||
this.type = type
|
||||
this.name = name
|
||||
this.viewPage = viewPage
|
||||
}
|
||||
}
|
||||
|
||||
export default function getUserTypeFactory(name, type) {
|
||||
let viewPage
|
||||
switch (type) {
|
||||
case 'superAdmin':
|
||||
viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
|
||||
break;
|
||||
case 'admin':
|
||||
viewPage = ['首页', '通讯录', '发现页', '应用数据']
|
||||
break;
|
||||
case 'normal':
|
||||
viewPage = ['首页', '通讯录', '发现页']
|
||||
break;
|
||||
default:
|
||||
throw new Error('参数错误,可选参数:superAdmin、admin、normal')
|
||||
}
|
||||
|
||||
return new User(name, type, viewPage)
|
||||
}
|
||||
```
|
||||
|
||||
### 抽象工厂模式
|
||||
|
||||
结合上文中的工厂,发现它不完全遵循 **SOLID法则** 中的开放封闭原则:对拓展开放,对修改封闭。
|
||||
|
||||
这篇文章我用一个手机从出产到上市使用的一个创建过程,首先我们知道,手机由两部分组成 **软件** ,**硬件**:
|
||||
|
||||
```js
|
||||
// 1-1. 手机初始化(抽象工厂):只定义
|
||||
class AbstractFactory {
|
||||
// 操作系统接口
|
||||
createOS() {
|
||||
throw new Error('抽象方法不允许直接调用,你需要将我重写')
|
||||
}
|
||||
|
||||
// 提供硬件接口
|
||||
createHardWare() {
|
||||
throw new Error('抽象方法不允许直接调用,你需要将我重写')
|
||||
}
|
||||
}
|
||||
|
||||
// 1-2. 具体工厂:负责干活
|
||||
class FakeStarFactory extends AbstractFactory {
|
||||
// 操作系统接口
|
||||
createOS() {
|
||||
// 安卓系统实例
|
||||
return new AndroidOS()
|
||||
}
|
||||
|
||||
// 提供硬件接口
|
||||
createHardWare() {
|
||||
// 高通硬件实例
|
||||
return new QualcommHardWare()
|
||||
}
|
||||
}
|
||||
|
||||
// 2-1. 抽象产品(软件):只定义
|
||||
class OS {
|
||||
controlHardWare() {
|
||||
throw new Error('抽象方法不允许直接调用,你需要将我重写')
|
||||
}
|
||||
}
|
||||
|
||||
// 2-2. 具体产品:安卓操作系统
|
||||
class AndroidOS extends OS {
|
||||
controlHardWare() {
|
||||
console.log('我会用安卓的方法去运行操作系统')
|
||||
}
|
||||
}
|
||||
|
||||
// 2-2. 具体产品:苹果操作系统
|
||||
class AppleOS extends OS {
|
||||
controlHardWare() {
|
||||
console.log('我会用苹果的方法去运行操作系统')
|
||||
}
|
||||
}
|
||||
|
||||
// 3-1. 抽象产品(硬件):只定义
|
||||
class HardWare {
|
||||
// 手机硬件的共性方法:根据命令运转
|
||||
operateByOrder() {
|
||||
throw new Error('抽象方法不允许直接调用,你需要将我重写')
|
||||
}
|
||||
}
|
||||
|
||||
// 3-2. 具体产品(硬件):高通
|
||||
class QualcommHardWare extends HardWare {
|
||||
operateByOrder() {
|
||||
console.log('我会用高通的方式去运转')
|
||||
}
|
||||
}
|
||||
|
||||
// 3-2. 具体产品(硬件):英特尔
|
||||
class InterHardWare extends HardWare {
|
||||
operateByOrder() {
|
||||
console.log('我会用英特尔的方式去运转')
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 创建手机
|
||||
const myMobile = new FakeStarFactory();
|
||||
// 初始化操作系统
|
||||
const myOS = myMobile.createOS();
|
||||
// 初始化硬件
|
||||
const myHardWare = myOS.createHardWare();
|
||||
|
||||
// 启动操作系统
|
||||
myOS.controlHardWare()
|
||||
|
||||
// 唤醒硬件命令
|
||||
myHardWare.operateByOrder()
|
||||
```
|
||||
|
||||
以上就是我们通过场景创建的四个重要的角色:
|
||||
|
||||
* 抽象工厂(抽象类,它不能被用于生成具体实例): 用于声明最终目标产品的共性。在一个系统里,抽象工厂可以有多个(大家可以想象我们的手机厂后来被一个更大的厂收购了,这个厂里除了手机抽象类,还有平板、游戏机抽象类等等),每一个抽象工厂对应的这一类的产品,被称为“产品族”。
|
||||
* 具体工厂(用于生成产品族里的一个具体的产品): 继承自抽象工厂、实现了抽象工厂里声明的那些方法,用于创建具体的产品的类。
|
||||
* 抽象产品(抽象类,它不能被用于生成具体实例): 上面我们看到,具体工厂里实现的接口,会依赖一些类,这些类对应到各种各样的具体的细粒度产品(比如操作系统、硬件等),这些具体产品类的共性各自抽离,便对应到了各自的抽象产品类。
|
||||
* 具体产品(用于生成产品族里的一个具体的产品所依赖的更细粒度的产品): 比如我们上文中具体的一种操作系统、或具体的一种硬件等。
|
||||
|
||||
总结下来,抽象工厂就类似 typescript 里面的 interface 申明对象。
|
||||
|
||||
|
||||
|
||||
### 单例模式
|
||||
|
||||
保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式。
|
||||
|
||||
#### 简单版
|
||||
|
||||
```js
|
||||
// ------------------- 单例模式 -------------------
|
||||
export default class Singleton {
|
||||
show() {
|
||||
console.log('我是一个单例对象')
|
||||
}
|
||||
|
||||
static getInstance() {
|
||||
if (!this.instance) {
|
||||
this.instance = new Singleton()
|
||||
}
|
||||
return this.instance
|
||||
}
|
||||
}
|
||||
|
||||
const s1 = Singleton.getInstance()
|
||||
const s2 = Singleton.getInstance()
|
||||
|
||||
s1 === s2 // => true
|
||||
```
|
||||
|
||||
#### 进阶版
|
||||
|
||||
实现一个 Storage
|
||||
|
||||
```js
|
||||
class Storage {
|
||||
constructor() {
|
||||
this.instance = null
|
||||
}
|
||||
|
||||
static getInstance() {
|
||||
if (!this.instance) {
|
||||
this.instance = new Storage()
|
||||
}
|
||||
return this.instance
|
||||
}
|
||||
|
||||
getItem(key) {
|
||||
return localStorage.getItem(key)
|
||||
}
|
||||
|
||||
setItem(key, value) {
|
||||
return localStorage.setItem(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 构造器模式
|
||||
|
||||
原型模式不仅是一种设计模式,它还是一种编程范式(programming paradigm),是 JavaScript 面向对象系统实现的根基。
|
||||
|
||||
```js
|
||||
// 一个构造函数
|
||||
class Asshole {
|
||||
constructor(name, age) {
|
||||
this.name = name
|
||||
this.age = age
|
||||
}
|
||||
|
||||
say() {
|
||||
console.log(`I'm asshole ${this.name},${this.age} years old.`)
|
||||
}
|
||||
}
|
||||
|
||||
const me = new Asshole('json', 28)
|
||||
```
|
||||
|
||||
**谈原型模式,其实是谈原型范式**,原型编程范式的核心思想就是利用实例来描述对象,用实例作为定义对象和继承的基础。在 JavaScript 中,原型编程范式的体现就是基于原型链的继承。这其中,对 **原型、原型链** 的理解是关键。
|
||||
|
||||
而面试官向你发问也并非是要求你破解人类未解之谜,多数情况下,他只是希望考查你对递归的熟练程度。所以递归实现深拷贝的核心思路,大家需要重点掌握(解析在注释里):
|
||||
|
||||
> 深拷贝没有完美方案,每一种方案都有它的边界 case
|
||||
|
||||
```ts
|
||||
const deepClone = (obj) => {
|
||||
// 如果是值类型或者不存在,直接返回
|
||||
if (typeof obj !== 'object' || obj === null) return obj
|
||||
|
||||
// 定义结果对象
|
||||
let copy = {}
|
||||
|
||||
// 如果对象是数组,则定义结果数组
|
||||
if (obj.constructor === Array) copy = []
|
||||
|
||||
// 遍历对象的 key
|
||||
for (let key in obj) {
|
||||
// 如果key是对象的自身属性
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
// 递归调用深拷贝方法
|
||||
copy[key] = deepClone(obj[key])
|
||||
}
|
||||
}
|
||||
|
||||
return copy
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 建造者模式
|
||||
|
||||
```js
|
||||
// 建造者模式 需要优化
|
||||
export default class Builder {
|
||||
constructor() {
|
||||
this.name = ''
|
||||
this.author = ''
|
||||
this.price = 0
|
||||
this.category = ''
|
||||
}
|
||||
|
||||
withName(name) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
withAuthor(author) {
|
||||
this.author = author
|
||||
return this
|
||||
}
|
||||
|
||||
withPrice(price) {
|
||||
this.price = price
|
||||
return this
|
||||
}
|
||||
|
||||
withCategory(category) {
|
||||
this.category = category
|
||||
return this
|
||||
}
|
||||
|
||||
build() {
|
||||
return {
|
||||
name: this.name,
|
||||
author: this.author,
|
||||
price: this.price,
|
||||
category: this.category
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
@ -1,40 +0,0 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 3
|
||||
---
|
||||
|
||||
## 装饰器模式
|
||||
|
||||
- 动态地给某个对象添加一些额外的职责,,是一种实现继承的替代方案
|
||||
- 在不改变原对象的基础上,通过对其进行包装扩展,使原有对象可以满足用户的更复杂需求,而不会影响从这个类中派生的其他对象
|
||||
|
||||
```js
|
||||
class Cellphone {
|
||||
create() {
|
||||
console.log('生成一个手机')
|
||||
}
|
||||
}
|
||||
class Decorator {
|
||||
constructor(cellphone) {
|
||||
this.cellphone = cellphone
|
||||
}
|
||||
create() {
|
||||
this.cellphone.create()
|
||||
this.createShell(cellphone)
|
||||
}
|
||||
createShell() {
|
||||
console.log('生成手机壳')
|
||||
}
|
||||
}
|
||||
// 测试代码
|
||||
let cellphone = new Cellphone()
|
||||
cellphone.create()
|
||||
|
||||
console.log('------------')
|
||||
let dec = new Decorator(cellphone)
|
||||
dec.create()
|
||||
```
|
@ -1,61 +0,0 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 22
|
||||
---
|
||||
|
||||
## 工厂模式
|
||||
|
||||
工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。
|
||||
|
||||
```js
|
||||
class User {
|
||||
constructor(type) {
|
||||
if (new.target === User) {
|
||||
throw new Error('抽象类不能实例化!')
|
||||
}
|
||||
this.type = type
|
||||
}
|
||||
}
|
||||
|
||||
class SuperAdmin extends User {
|
||||
constructor(name) {
|
||||
super('superAdmin')
|
||||
this.name = name
|
||||
this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
|
||||
}
|
||||
}
|
||||
class Admin extends User {
|
||||
constructor(name) {
|
||||
super('admin')
|
||||
this.name = name
|
||||
this.viewPage = ['首页', '通讯录', '发现页', '应用数据']
|
||||
}
|
||||
}
|
||||
class Normal extends User {
|
||||
constructor(name) {
|
||||
super('normal')
|
||||
this.name = name
|
||||
this.viewPage = ['首页', '通讯录', '发现页']
|
||||
}
|
||||
}
|
||||
|
||||
export default function getUserTypeFactory(type) {
|
||||
switch (type) {
|
||||
case 'superAdmin':
|
||||
return SuperAdmin
|
||||
break;
|
||||
case 'admin':
|
||||
return Admin
|
||||
break;
|
||||
case 'normal':
|
||||
return Normal
|
||||
break;
|
||||
default:
|
||||
throw new Error('参数错误,可选参数:superAdmin、admin、normal')
|
||||
}
|
||||
}
|
||||
```
|
@ -1,65 +0,0 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 5
|
||||
---
|
||||
|
||||
## 代理模式
|
||||
|
||||
是为一个对象提供一个代用品或占位符,以便控制对它的访问
|
||||
|
||||
### 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ES6 版
|
||||
|
||||
```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)
|
||||
},
|
||||
listenGoodMood: function(fn) {
|
||||
setTimeout(function() {
|
||||
fn()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
xiaoming.sendFlower(B)
|
||||
```
|
@ -1,30 +0,0 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 2
|
||||
---
|
||||
|
||||
## 单例模式
|
||||
|
||||
一个类只有一个实例,并提供一个访问它的全局访问点。
|
||||
|
||||
```js
|
||||
// ------------------- 单例模式 -------------------
|
||||
export default class Singleton {
|
||||
constructor(name, creator, products) {
|
||||
this.name = name
|
||||
this.creator = creator
|
||||
this.products = products
|
||||
}
|
||||
|
||||
static getInstance(name, creator, products) {
|
||||
if (!this.instance) {
|
||||
this.instance = new Singleton(name, creator, products)
|
||||
}
|
||||
return this.instance
|
||||
}
|
||||
}
|
||||
```
|
@ -1,41 +0,0 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 7
|
||||
---
|
||||
|
||||
## 策略模式
|
||||
|
||||
```js
|
||||
class CalculateMoney {
|
||||
constructor(type, money) {
|
||||
this.money = money
|
||||
return this.switchStrategy(type, money)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let calculateMoney = new CalculateMoney('', 10000)
|
||||
// => 4000000
|
||||
```
|
191
docs/fea/pattern/structure.md
Normal file
191
docs/fea/pattern/structure.md
Normal file
@ -0,0 +1,191 @@
|
||||
---
|
||||
nav:
|
||||
title: 前端
|
||||
path: /fea
|
||||
group:
|
||||
title: 💊 设计模式
|
||||
order: 4
|
||||
---
|
||||
|
||||
## 结构型
|
||||
|
||||
结构型模式封装的是对象之间组合方式的变化,目的在于灵活地表达对象间的配合与依赖关系;
|
||||
|
||||
### 适配器模式
|
||||
|
||||
将一个类的接口转化为另外一个接口,以满足用户需求,使类之间接口不兼容问题通过适配器得以解决。
|
||||
|
||||
```js
|
||||
import react from 'react';
|
||||
|
||||
class Adapter {
|
||||
constructor(config) {
|
||||
if (!config || typeof config === 'object') {
|
||||
return this.reLoad(config)
|
||||
} else {
|
||||
throw new Error('传递的参数必须为一个对象!')
|
||||
}
|
||||
}
|
||||
|
||||
reLoad(arr) {
|
||||
let newObj = {}
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const item = arr[i]
|
||||
newObj[item.name] = item.age
|
||||
}
|
||||
return newObj
|
||||
}
|
||||
}
|
||||
|
||||
let aer = new Adapter([{name: 'david', age: 2}])
|
||||
// => {david: 2}
|
||||
```
|
||||
|
||||
### 装饰器模式
|
||||
|
||||
- 动态地给某个对象添加一些额外的职责,,是一种实现继承的替代方案
|
||||
- 在不改变原对象的基础上,通过对其进行包装扩展,使原有对象可以满足用户的更复杂需求,而不会影响从这个类中派生的其他对象
|
||||
- 遵循拓展不修改的 SOLID 原则
|
||||
|
||||
#### 简单版
|
||||
|
||||
```jsx
|
||||
import React, { useRef, useState, useEffect } from 'react';
|
||||
|
||||
class Modal {
|
||||
constructor(opt = {}) {
|
||||
const { dom } = opt
|
||||
|
||||
this.dom = dom
|
||||
}
|
||||
|
||||
show() {
|
||||
this.dom.innerHTML = '卧槽';
|
||||
this.dom.style.display = 'block'
|
||||
this.dom.style.width = '200px'
|
||||
this.dom.style.textAlign = 'center'
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.dom.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
class DecoratorModal {
|
||||
constructor(_oldModal) {
|
||||
this._oldModal = _oldModal
|
||||
}
|
||||
|
||||
show() {
|
||||
this._oldModal.show()
|
||||
|
||||
this._oldModal.dom.innerHTML = '添加背景+文字减淡+圆角'
|
||||
this._oldModal.dom.style.color = '#aaa'
|
||||
this._oldModal.dom.style.borderRadius = '5px'
|
||||
}
|
||||
|
||||
hide() {
|
||||
this._oldModal.hide()
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const modalRef = useRef(null)
|
||||
const [modal, setModal] = useState(null)
|
||||
// 案例:原本有个按钮,新的需求要将按钮样式置灰,并且文案改为 快去登录
|
||||
const openModal = () => {
|
||||
modal.show()
|
||||
}
|
||||
|
||||
const hideModal = () => {
|
||||
modal.hide()
|
||||
}
|
||||
|
||||
const decoratorModal = () => {
|
||||
let dom = new DecoratorModal(modal)
|
||||
|
||||
setModal(dom)
|
||||
}
|
||||
|
||||
const normalModal = () => {
|
||||
let dom = new Modal({
|
||||
dom: modalRef.current
|
||||
})
|
||||
|
||||
setModal(dom)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
normalModal()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="decorator">
|
||||
<button onClick={openModal} >打开弹框</button>
|
||||
<button onClick={hideModal} >关闭弹框</button>
|
||||
<button onClick={decoratorModal} >添加适配器</button>
|
||||
<button onClick={normalModal} >清除适配器</button>
|
||||
<div ref={modalRef} style={{ display: 'none', marginTop: '20px', padding: '10px 20px', border: '1px solid #eee'}} ></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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### ES5 版
|
||||
|
||||
```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)
|
||||
},
|
||||
listenGoodMood: function(fn) {
|
||||
setTimeout(function() {
|
||||
fn()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
xiaoming.sendFlower(B)
|
||||
```
|
Loading…
Reference in New Issue
Block a user