现代设计模式讲解,包含React用例
设计模式
- Singleton Pattern 单例模式
- Decorator Pattern 装饰器模式/外观模式
- HOC Pattern 高阶组件模式
- Provider Pattern 生产者模式
- Proxy Pattern 代理模式
- Bridge Pattern/Command Pattern 桥接模式/命令行模式
- Extend Pattern 继承模式/模版方法模式
- Mediator Pattern 中间件模式/中介者模式/调节者模式,依赖注入/IoC思维
- Mixed Pattern 混合模式
- Obverse Pattern 观察者模式/订阅模式
- Factory Pattern 工厂模式
- Adapter Pattern 适配器模式
- Visitor Pattern 访问者模式
- Strategy Pattern 策略模式
- Iterator Pattern 迭代器模式
- Composite Pattern 组合模式/部分-整体模式
- 备忘录模式
- Chain of Responsibility Pattern 职责链模式
- Flyweight Pattern 享元模式
- State Pattern 状态模式
Singleton Pattern 单例模式
生成唯一实例,如创建一个唯一的遮罩层,给所有弹窗方法共用
const getModelWindow = (() => {let singlereturn () => {if (single) {return single}single = document.createElement('div')document.body.appendChild(single)return single}
})()
示例里用一个变量保存函数返回值,这样除了第一次调用函数getModelWindow
会创建实例以外,后续调用将返回第一次存储的结果single
;
Decorator Pattern 装饰器模式/外观模式
内部调用多个不同的方法去实现功能,而自身作为一个整体供给外部使用。要注意和装饰器@Controller
这种是不一样的,一个是设计模式,一个是类似寄生模式的新特性。
const stopEvent = event => {event.stopPropagation()event.preventDefault()
}
const logger = str => console.log(str)
const errorHandler = err => console.error(err)
const ClickListener = function (id, callback = () => {}) {// 完成监听、阻止默认事件、日志、错误处理等document.getElementById(id).addEventListener("click", event => {stopEvent(event)logger("calling event")try {callback(event)} catch (err) {errorHandler(err)}});
}
ClickListener("button", event => {// go on do something...
})
HOC Pattern 高阶组件模式
相比装饰器模式更注重包裹众多方法处理,HOC模式更注重包裹传入的对象,帮其实现通用行为:
// 定义Container.jsx
export default function Container({Component}) {const injectProps = {mainColor: "#000000"}return (<div className="contain fullscreen"><Component {...injectProps} /></div>)
}// 子组件将能享受到父容器的包裹
function Child(props) {return (<p>Output: {props.mainColor}</p>)
}import Container from "Container"
// 使用
ReactDom.render(<Container Component={Child}/>)
Provider Pattern 生产者模式
HOC模式结合单例模式的具体应用,面对像React/Vue框架里相邻和嵌套的多个组件之间的共享相同的状态数据和方法,为了避免层层传递而使用context
解决的模式
定义上下文,数据和相关方法都在里面:
// ThemeContext.jsx
import {useState, createContext} from "react"export const ThemeContext = createContext({})
export default function ThemeProvider({children}) {const [theme, setTheme] = useState(false);return (<ThemeContext.Provider value={{theme, setTheme}}>{children}</ThemeContext>)
}
设定上下文作用范围,这里用在ListPage
组件上,这样内部的子组件Filter
和Info
都能使用该上下文内容:
// ListPage.jsx
import ThemeProvider from "@/context/ThemeContext"
import Filter from "@/component/Filter"
import Info from "@/component/Info"export default function ListPage({listData}) {return (<ThemeProvider><Filter/>{listData.map(item => <Info data={item}/>)}</ThemeProvider>)
}
在Filter组件中使用上下文,调用方法修改状态数据:
// Filter.jsx
import {useContext} from "react"
import {ThemeContext} from "@/context/ThemeContext"export default function Filter() {const {theme, setTheme} = useContext(ThemeContext)return (<button type="button" onClick={() => setTheme(!theme)}>Switch</button>)
}
在Info组件中使用上下文,调用状态数据:
// Info.jsx
import {useContext} from "react"
import {ThemeContext} from "@/context/ThemeContext"export default function Info({data}) {const {theme, setTheme} = useContext(ThemeContext)return (<div className={theme ? "bg-light" : "bg-dark"}><h3>{data.title}</h3><p>{data.desc}</p></div>)
}
Proxy Pattern 代理模式
通过附加额外方法属性完成不属于原对象的功能,一般用来写赋值验证或者输出日志。
const formData = {name: "defaultName",age: 0
};
const superFormData = new Proxy(formData, {get: (obj, prop) => {console.log(`the ${prop} value is : ${obj[prop]}`);return Reflect.get(obj, prop);},set: (obj, prop, value) => {if (prop === "age") {if (typeof value !== "number" || value <= 0 || value > 150) {return false;}Reflect.set(obj, prop, value);}}
});
superFormData.name // 会同时输出到命令行
superFormData.age = "18" // 不满足条件,赋值失败
superFormData.age = 18 // 满足条件才能赋值成功
Bridge Pattern/Command Pattern 桥接模式/命令行模式
通过传递处理方法,解耦拆分原函数,完成独立变化。如把单例模式拆分成一个抽象函数和实现函数,有点类似代理模式的另类实现,IoC控制反转也是类似操作
const Controller = dependence => {let resultreturn () => {return result || (result = dependence.apply(this, arguments))}
}
const injecter = () => document.body.appendChild(document.createElement('div'))
const bridgeDone = Controller(injecter);
Extend Pattern 继承模式/模版方法模式
在父类中声明原型方法,在子类中可以重载或者定义新功能
class Human {constructor(name) {this.name = name}walk() {console.log("Walking~~")}move() {return this.walk()}
}class Superman extends Human {constructor(name = "Clack") {super(name)}// 定义新方法,强化原本的类fly() {console.log("Flying~~")}// 重载类方法move() {return this.fly()}
}const superman = new Superman()
superman.move() // flying~~
继承模式适用于固定且统一的类,例如上面的Superman
继承Human
,而一个Transformers
变形金刚或者Car
汽车肯定不会继承Human
,因此如果需要定义不属于原类的方法,但该类又需要使用,例如定义Car
相关方法,应该适用代理模式或者Ioc思维去实现。
Mediator Pattern 中间件模式/中介者模式/调节者模式,依赖注入/IoC思维
class Human {constructor(name, vehicle, equitment) {this.name = namethis.vehicle = vehiclethis.equitment = equitment}walk() {console.log("Walking~~")}move() {vehicle?.move() ?? this.walk()}support(event) {this.vehicle[event] ?? this.vehicle[event]()this.equitment[event] ?? this.equitment[event]()}
}class Car {fire() {console.log("Missile fire~~")}move() {console.log("Car moving~~")}
}class Gun {fire() {console.log("Gun fire~~")}
}const batman = new Human("batman", new Car(), new Gun())
batman.move() // Car moving~~
batman.support("fire") // Missile fire~~,Gun fire~~
中间件还有另一种借助观察者模式实现的多重包裹,类似Koa中间件和父子组件事件:
class App {_callback(params) {console.log("无论多少中间件,此乃内部最终返回")}watch(callback) {const _origin = this._callbackthis._callback = params => callback(params, () => _origin(params))}invoke(...params) {return this._callback(params)}
}const app = new App()
app.watch((params, next) => {console.log("先定义,但是后触发,相当于最后防线:1")next()
})
app.watch((params, next) => {console.log("后定义,但是先触发,相当于预处理:2")next()
})
app.invoke("some")
Mixed Pattern 混合模式
用来增强对象或者类的功能,关键在于通过混合器方法创建新对象或新类达成目标
class Human {}const Mixer = Class => class extends Class {callHelp() {console.log("Help!!!")}
}
const humanWithSuperman = new (Mixer(Human))()
humanWithSuperman.callHelp()
Obverse Pattern 观察者模式/订阅模式
抽象化一个函数,当相关动作发生时,通过调用其他函数完成后续动作,最常见的是事件监听。
网页内置的事件订阅
document.getElementById("button").addEventListener("click", event => {console.log("这就是订阅模式")
})
自定义订阅
const target = {_callback: [],subscribe(callback) {_callback.push(callback)},dispatch() {_callback.reduce((prev, item) => item(), "")}
};
target.subscribe(() => console.log("1, do this..."))
target.subscribe(() => console.log("2, do that..."))
target.dispatch()
Factory Pattern 工厂模式
封装了对输入的处理和输出统一格式内容,内部可以新建不同类实例,或者是完成内容组装等
const MovingSuit = function (destination) {const distance = getDistance(destination)const human = new Human()return distance > 100 ? {driver: human,name: `${human.name} drive to ${destination}`,vihicle: new Car()} : {rider: human,name: `${human.name} ride to ${destination}`,vihicle: new Bicycle()}
};
const shopping = MovingSuit("成华大道") // in bicycle
const traveller = MovingSuit("北京") // in car
Adapter Pattern 适配器模式
将一个函数或类实例输出的内容转变成另外一个函数或类实例可使用的结构,常用于将接口返回的数据变成页面所需显示内容
const adapter = data => {return {...data,name: data.nickname || "匿名",image: data.images.length ? data.images[0] : "",date: (new Date(data.createTime)).toLocaleDateString()}
};
Visitor Pattern 访问者模式
抽象一个函数作为访问者,符合条件的人都可以作为被访问者调用它,这种方法原生js已实现,那就是apply()和call()方法
// 访问者
var Visitor = {};
Visitor.push = function () {return Array.prototype.push.apply(arguments);
};
// 被访问者
var obj = {};
obj.push = Visitor.push;
obj.push('haha');
console.log(obj.length);
Strategy Pattern 策略模式
为减少大量的if/else语法,通过类型或事件区分为不同独立方法完成处理返回,如提交表单前,对有非空、长度、禁用词验证等。
const validata = function (checkOpt) {const handler = {notNull(value) {return value !== ''},dirtyWords(value, words) {return !words.length || words.reduce((prev, item) => prev && value.indexOf(item) === -1, true)},maxLength(value, maxLen) {return value.length <= maxLen}}let result = truefor (let type in checkOpt) {if (result && typeof handler[type] === 'function') {if (!handler[type](this.value, checkOpt[type])) {console.log(type)result = false}}}return result
};
const inputElement = {value: "is it true?"
}
validata.call(inputElement, {notNull: true,dirtyWords: ['fuck', 'shit'],maxLength: 30
})
Iterator Pattern 迭代器模式
封装好一些迭代方法用于事务场合
const ObjForEach = (obj, fn) => {for (let i in obj) {const c = obj[i];if (fn.call(c, i, c) === false) {return false;}}
};
// 使用
ObjForEach({"a": 1, "b": 2}, (i, n) => {console.log(i + ' is ' + n);
});
Composite Pattern 组合模式/部分-整体模式
好处是用户不用确定对象是简单还是复杂结构、是单个还是多个的情况下,函数都可完成所有工作,如jQuery的Dom选择器中不会关注有一个还是多个Dom对象,调用方法时都会自动完成,例子略
备忘录模式
实际上就是利用了查找变量时,若函数内没有该变量,会自动查找上一级函数的变量,此时上一级函数的变量仍存储有内容可供使用,常见于匿名回调函数调用上一级函数的变量
const getPageData = function () {let cacheData = {},result;return (pageIndex = 1) =>new Promise(resolve => {if (cacheData[pageIndex]) {result = cacheData[pageIndex];resolve(result);} else {fetch('cgi.xx.com/xxx').then(data => {cacheData[pageIndex] = dataresolve(data)})}})
}()
Chain of Responsibility Pattern 职责链模式
对象A向对象B发起请求,如果B不处理,可以把请求转给C,如果C不处理,又可以把请求转给D。一直到有一个对象愿意处理这个请求为止。
Dom事件的冒泡捕获机制就是类似方式,点击事件发生时,会在当前节点触发,并依次向最高父节点传递。
Koa中间件对请求和响应处理也是类似方式。
Flyweight Pattern 享元模式
通过共享一部分数据,达到减少程序所需的内存。例如无限下拉列表中,通过确定出现在可视区域中的实际行数,加载时无需创建更多li标签,而是利用已经’消失‘在可视区域外的li标签重复利用。
State Pattern 状态模式
主要可以用于这种场景:1、一个对象的行为取决于它的状态;2、一个操作中含有庞大的条件分支语句,为了集中管理这些状态和代码,引入一个状态类,内部记录当前状态和完成修改状态,外部可以获取当前状态和修改状态。
enum State {JUMP,STOP,ATTACK,FORWARD,BACKWARD,DEFENSE
}class StateManager {currState: State.STOPget actions() {return {jump(state) {currState = State.JUMP},wait(state) {currState = State.STOP},attack(state) {// 增加攻击间隔if (currState === State.ATTACK)wait(300)currState = State.ATTACK},defense(state) {// 跳跃的时候不能防御if (currState === State.JUMP)return false;currState = State.DEFENSE;}}}
};
var character = StateManager()
character.actions.defense()
现代设计模式讲解,包含React用例相关推荐
- 实例讲解基于 React+Redux 的前端开发流程
前言:在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 star 数达 42000 +,超过了 jquery 的 39000+,也即将超过前几年比较火的an ...
- 【设计模式】-创造篇-单例
单例定义 单例模式(Singleton)是一种非常简单且容易理解的设计模式.顾名思义,单例即单一的实例,确切地讲就是指在某个系统中只存在一个实例,同时提供集中.统一的访问接口,以使系统行为保持协调一致 ...
- java饿汉式有啥作用,Java面试 - 什么是单例设计模式,为什么要使用单例设计模式,如何实现单例设计模式(饿汉式和懒汉式)?...
什么是单例设计模式? 单例设计模式就是一种控制实例化对象个数的设计模式. 为什么要使用单例设计模式? 使用单例设计模式可以节省内存空间,提高性能.因为很多情况下,有些类是不需要重复产生对象的.如果重复 ...
- 设计模式是什么鬼(单例)
转自:设计模式是什么鬼(单例) 之前我们讲过面向对象以及封装.继承.多态三大特性,底子打好了那我们就把设计模式一个个拆开来看看到底都是神些什么鬼,我们先从简单的单例说起吧.单例,顾名思义,整个系统其实 ...
- IOS设计模式第二篇之单例设计模式
现在我们的组件已经有组织了.你需要从其他的地方得到数据,你也可以创建一个API类管理数据这个下个设计模式单例里面介绍. 这个单例设计模式确保这个类仅仅拥有一个实例,并且为这个实例提供一个全局的访问点. ...
- Ruby设计模式透析之 —— 单例(Singleton)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8868758 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...
- 对于java程序语言的单例设计模式讲解
1.设计模式:解决某一类问题最行之有效的方法.(java中有23种通用设计模式) 单例设计模式:解决一个类在内存中只存在一个对象. 2.单例设计模式有两种方式: 1)饿汉式 先初始化对象.当类一进内存 ...
- Java代码设计模式讲解二十三种设计模式
设计模式 文章目录 设计模式 一.创造型设计模式 1.1 单例模式 1.1.1 饿汉式单例模式 1.1.2 懒汉式单例模式 (1)线程不安全的情况 (2)线程安全的情况 1. 实例化的方法上加sync ...
- GOF设计模式之1:单例设计模式
1.单例设计模式核心作用: 保证一个类只有一个实例,并且提供了访问该实例的全局访问点 2.常见应用场景: window的任务管理器 项目中读取配置文件一般也是一个单例模式 数据库连接池的设计也是采用单 ...
最新文章
- 六周第四次课(5月2日)
- c#一个分页控件的例子
- 公钥密码--Diffie-Hellman密钥协商算法
- 【牛客网】NC31 第一个只出现一次的字符
- X86汇编语言从实模式到保护模式11:指令格式及操作尺寸
- MyBatis和Hibernate的优缺点对比。
- 宏基ACER Aspire R3600 REVO离子平台
- c++ qt qlistwidget清空_Qt音视频开发16-mpv通用接口
- DHCP Relay 配置教程
- html中左三角怎么写,css3三角形怎么写?
- 1分钟彻底搞懂关于nginx的proxy_pass
- 机器人课做的一个悬崖识别自动变向的一个小车
- 手机、平板与手表,华为一个都不能少
- 需要用计算机权限才能删除,您需要计算机管理员提供的权限才能对此文件进行更改,删不掉文件怎么处理...
- Theano官方文档的测试和总结(1):安装、基础语法、逻辑斯蒂回归
- linux之ssh命令
- Vue2.x动态添加路由实现
- EBS 清除node信息 fnd_conc_clone.setup_clean
- 【Python | X先生】从00-90后的微信昵称,发现如下规律。。。
- Leetcode 414. 第三大的数(详解 C语言实现)