|- 工厂模式
|- 单例模式
|- 原型模式
|- 装饰器模式
|- 代理模式
|- 策略模式(行为型)
|- 状态模式(行为型)
|- 观察者模式(行为型)
|- 迭代器(行为型)
设计模式原则:
开放封闭原则的内容:对拓展开放,对内修改封闭
工厂模式:
what ?
将创建对象的过程单独封装,这样的操作就是工厂模式
- 抽象工厂-> 具体工厂-> 抽象产品 -> 具体产品
- 抽象工厂是佐证“开放封闭原则”的良好素材
//工厂模式示例
function User(name, age, career, work) {
this.name = name;
this.age = age;
this.career = career;
this.work = work;
}
function Factory(name, age, career) {
let work;
switch(career) {
case 'coder':
work = ['写代码'];
break;
case 'productor':
work = ['生产'];
break;
...
}
return new User(name, age, career, work)
}
单例模式
what ?
- 保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式。
- 唯一数据源 (SSOT)
how ?
- eg: 在vuex中的应用:一个 Vue 实例只能对应一个 Store
Vue.use(Vuex); 只注入一次vue的实例只会install一次vuex插件,保证store的唯一性
demo
- 利用静态static 方法可以创建单例模式
class SingleSong {
show() { console.log('sing....') }
static getInstance() {
if(!SingleSong.instance) {
SingleSong.instance = new SingleSong();
}
return SingleSong.instance;
}
}
// 方法2: 利用闭包创建单例
SingleSong.getInstance = (function(){
let instance = null;
return function() {
if(!instance) {
instance = new SingleSong();
}
return instance;
}
})()
- 利用闭包创建一个单例模式modal
const Modal = (function() {
let modal = null
return function() {
if(!modal) {
modal = document.createElement('div')
modal.innerHTML = '您还未登录哦~'
modal.id = 'modal'
modal.style.display = 'none'
document.body.appendChild(modal)
}
return modal
}
})()
const modal = new Modal()
- 面试题: 实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现方法 setItem(key,value) 和 getItem(key)。
// 方法一:es6
class Storage {
static getIns() {
if(!Storage.instance) {
Storage.instance = new Storage();
}
return Storage.instance;
}
getItem(key) {
return localStorage.getItem(key)
}
setItem(key, value) {
localStrage.setItem(key, value)
}
}
// 方法二:
function StorageBase() {}
Storage.prototype.getItem = function(key) { return localStorage.getItem(key)}
Storage.prototype.setItem = function(key, value) { localStrage.setItem(key, value)}
const Storage = (function(){
let instance = null;
return function() {
if(!instance) {
instance = new StorageBase();
}
return instance;
}
})()
原型模式
- JavaScript 这门语言面向对象系统的根本
装饰器模式:
what ?
- 装饰器模式,又名装饰者模式。它的定义是“在不改变原对象的基础上,通过对其进行包装拓展,使原有对象可以满足用户的更复杂需求”
- 实例是在我们的代码运行时动态生成的,而装饰器函数则是在编译阶段就执行了。所以说装饰器函数真正能触及到的,就只有类这个层面上的对象
how ?
- HOC 、 redux、axios 中的应用
- HOC (Higher Order Component) 即高阶组件。它是装饰器模式在 React 中的实践
// react 中的高阶组件:
import React, { Component } from 'react'
const BorderHoc = WrappedComponent => class extends Component {
render() {
return <div style={{ border: 'solid 1px red' }}>
<WrappedComponent />
</div>
}
}
export default borderHoc
demo
// 定义打开按钮
class OpenButton {
// 点击后展示弹框(旧逻辑)
onClick() {
const modal = new Modal()
modal.style.display = 'block'
}
}
// 定义按钮对应的装饰器
class Decorator {
// 将按钮实例传入
// 重点:
constructor(open_button) {
this.open_button = open_button
}
onClick() {
this.open_button.onClick()
// “包装”了一层新逻辑
this.changeButtonStatus()
}
changeButtonStatus() {
this.changeButtonText()
this.disableButton()
}
// 单一职责
disableButton() {
const btn = document.getElementById('open')
btn.setAttribute("disabled", true)
}
// 单一职责
changeButtonText() {
const btn = document.getElementById('open')
btn.innerText = '快去登录'
}
}
装饰器在redux中的应用:
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import action from './action.js';
function mapStateToProps(state){
return state.app;
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(action, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps);
axios 中的适配器
- axios本身就用到了我们的适配器模式
- 这正是一个好的适配器的自我修养——把变化留给自己,把统一留给用户
// 用fetch封装一个HttpUtils:
export default class HttpUtils{
// get请求
static get(url)
return new Promise((resolve, reject) => {
fetch(url)
.then(result => {
resolve(result);
})
.catch(err => {
reject(err);
})
})
// post请求
static post(url, data){
return new Promise((resolve, reject) => {
fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: this.changeData(data)
})
.then(response => response.json())
.then(result => {
resolve(result);
})
.catch(err => {
reject(err);
})
}
}
// body请求体的格式化方法
static changeData(obj) {
var prop,
str = ''
var i = 0
for (prop in obj) {
if (!prop) {
return
}
if (i == 0) {
str += prop + '=' + obj[prop]
} else {
str += '&' + prop + '=' + obj[prop]
}
i++
}
return str
}
}
代理模式
how ?
- proxy, 缓存
Proxy
es6中的代理:new Proxy(obj, {
get: function(){},
set: function(){}
})
缓存代理:
function addAll(){
let result = 0;
const let = arguments.length;
for(let i =0 ;i < len; i++) {
result += arguments[i];
}
return result;
}
const proxyAddAll = (function(){
const resultCache = {};
return function(){
//所有参数转换为字符串
let args = Array.prototype.join.call(arguments, ',');
if(args in resultCache) {
return resultCache[args];
}
return resultCache[args] = addAll(...arguments);
}
})()
行为型-策略模式:
- 对算法的封装,不依赖于主体
// 定义一个询价处理器对象
const priceProcessor = {
pre(originPrice) {
if (originPrice >= 100) {
return originPrice - 20;
}
return originPrice * 0.9;
},
onSale(originPrice) {
if (originPrice >= 100) {
return originPrice - 30;
}
return originPrice * 0.8;
},
back(originPrice) {
if (originPrice >= 200) {
return originPrice - 50;
}
return originPrice;
},
fresh(originPrice) {
return originPrice * 0.5;
},
};
行为型-状态模式:
状态模式主要解决的是当控制一个对象++状态的条件表达式过于复杂时++的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
- 指责分离
- 开放封闭
- 主体关联
class CoffeeMaker {
constructor() {
// 这里略去咖啡机中与咖啡状态切换无关的一些初始化逻辑
// 初始化状态,没有切换任何咖啡模式
this.state = 'init';
// 初始化牛奶的存储量
this.leftMilk = '500ml';
}
stateToProcessor = {
that: this, // 重点!!!
american() {
// 尝试在行为函数里拿到咖啡机实例的信息并输出
console.log('咖啡机现在的牛奶存储量是:', this.that.leftMilk)
console.log('我只吐黑咖啡');
},
latte() {
this.american()
console.log('加点奶');
},
vanillaLatte() {
this.latte();
console.log('再加香草糖浆');
},
mocha() {
this.latte();
console.log('再加巧克力');
}
}
// 关注咖啡机状态切换函数
changeState(state) {
this.state = state;
if (!this.stateToProcessor[state]) {
return;
}
this.stateToProcessor[state]();
}
latteProcress() {
this.americanProcess();
console.log('加点奶');
}
vanillaLatteProcress() {
this.latteProcress();
console.log('再加香草糖浆');
}
mochaProcress() {
this.latteProcress();
console.log('再加巧克力');
}
}
const mk = new CoffeeMaker();
mk.changeState('latte');
行为型:观察者模式
- 角色划分 --> 状态变化 --> 发布者通知到订阅者,这就是观察者模式的“套路”
- Event Bus/ Event Emitter
class EventEmitter {
constructor(){
// handlers是一个map,用于存储事件与回调之间的对应关系
this.handlers = {}
}
on(eventName, cb) {
if(!this.handlers[eventName]) {
// 初始化事件为空数组
this.handlers[eventName] = []
}
// 把回调函数推入目标事件的监听函数队列里去
this.handler[eventName].push(cb);
}
// emit方法用于触发目标事件,它接受事件名和监听函数入参作为参数
emit(eventName, ...args){
if(this.handler[eventName]){
// 如果有,则逐个调用队列里的回调函数
this.handlers[eventName].forEach(callback => {
callback(...args);
})
}
}
// 移除某个事件回调队列里的指定回调函数
// 一个监听事件可以对应多个回调函数
off(eventName, cb) {
const cbs = this.handles[eventName];
const index = cbs.indexOf(cb);
if(index !== -1) {
cbs.splice(index,1)
}
}
// 为事件注册单次监听器
once(eventName, cb) {
// 对回调函数进行包装,使其执行完毕自动被移除
const wrapper = (...args) => {
cb.apply( ...args);
// 注意!!
this.off(eventName, warpper);
}
this.on(eventName, wrapper);
}
}
- 观察者模式是只有发布者和订阅者。
- 发布-订阅模式是有中间机构——事件中心,实现了发布者和订阅者的完全解耦。
行为型:迭代器
- forEach无法遍历类数组(dom节点数组)
- 通用遍历方法:for...of...
- es6:只要具备Symbol.iterator属性就可以被遍历。
书籍:
- head first 设计模式
- 设计模式:可复用面向对象软件的基础
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!