一、单例模式
类只有一个实例,像BOM这个全局对象就是单例模式,还有单独创建一个对象字面量,也是单例模式,下面讲述单例模式的实现:
class Aoteman { constructor(name, age) { this.name = name this.age = age } // 实现单例模式 static getInstance(name, age) { if (!this.instance) { this.instance = new Aoteman(name, age) } return this.instance } Ability = data => { console.log(this.name + ' can ' + data) } } const dijia = new Aoteman('dijia', '2022') console.log(dijia.name) dijia.Ability('X-ray') let tailuo = Aoteman.getInstance('tailuo', '1990') console.log(tailuo.name) tailuo.Ability('Y-ray') let aidi = Aoteman.getInstance('aidi', '1990') console.log(aidi.name) tailuo.Ability('Z-ray') console.log('---------------------') console.log(dijia === tailuo) console.log(tailuo === aidi)
上面的方式实现,只能调用getInstance方法才能创建单例,如果用户再次使用new来创建实例,还是不可行,所以还需要对上述予以工厂模式封装:
const singleFactory = (...rest) => { return Aoteman.getInstance(...rest) }
使用场景:发布订阅场景,我们需要在一个地方进行订阅,在另一个地方进行发布,这样就需要保证在不同文件中访问到的是同一个实例。
class PubSub { constructor() { this.listeners = {} } publish(event, data) { if (!this.listeners[event]) { return; } this.listeners[event].forEach(listener => { listener(data); }) } subscribe(event, callback) { if (!this.listeners[event]) { this.listeners[event] = [] } this.listeners[event].push(callback); } } export default new PubSub
二、工厂模式
- 优点:一个工厂创建同一类对象,更好的归类创建
- 抽象工厂模式的缺点就是,如果需要增加新的产品,比如要生产可乐周边玩偶,这就需要对原有的抽象工厂接口进行改造,不符合开闭原则。
function CreateElement(type) { switch (type) { case 'Input': return new Input() break; case 'Div': return new Div() break; default: throw new Error('无当前产品') } } function Input() { return document.createElement('input') } function Div() { return document.createElement('div') } //test const input = new CreateElement('Input'); const div = new CreateElement('DIV'); console.log(input) // input console.log(div) // div
class User { constructor(name) { this.name = name } SetRoleType(type) { switch (type) { case 'Admin': return new UserAdmin() break case 'Member': return new UserMember() break default: throw new Error('Set Error!') } } GetName = () => { console.log('this name is: ' + this.name) } } class UserAdmin extends User { constructor(name) { super(name) this.name = name } RoleInfo = () => { console.log('Type is Admin ') } } const zhangsan = new User('zhangsan') zhangsan.GetName() zhangsan.SetRoleType('Admin').RoleInfo()
建造者模式
/** * 建造者模式 */ /* 建造者 */ function ComputerBuilder(brand) { this.brand = brand } ComputerBuilder.prototype.buildCPU = function (type) { switch (type) { case 'inter': this.cpu = 'inter处理器' break; case 'AMD': this.cpu = 'AMD处理器' break; } return this } ComputerBuilder.prototype.buildMemory = function (mSize) { thgis.mSize = '内存' + mSize + 'G' return this } ComputerBuilder.prototype.buildDisk = function (dSize) { this.dSize = '硬盘' + dSize + 'G' return this } /* 厂家,负责组装 */ function computerDirector(brand, type, mSize, dSize) { const _computer = new ComputerBuilder(brand) _computer.buildCPU(type) .buildMemory(mSize) .buildDisk(dSize) return _computer } //test const com = computerDirector('联想', 'inter', 16, 500); console.log(com); // ComputerBuilder {brand: "联想", cpu: "inter 处理器", mSize: "内存16G", dSize: "硬盘500G"}
代理模式
/** * 代理模式 */ /* 目标 */ function sendMsg(msg) { console.log(msg) } /* 代理 */ function ProxyMsg(msg) { if (!msg) { console.log('msg is empty') return } msg = '我要发送的数据是' + msg sendMsg(msg) } // test ProxyMsg('您好!')
享元模式
/** * 享元模式 */ /* 享元对象 */ function Shape(shape) { this.shape = shape } shape.prototype.draw = function () { console.log(`画了一个${this.shape}`) } /* 享元工厂 */ const ShapeFactory = (function () { const dataMap = {} return { getShapeContext(shape) { if (dataMap[shape]) return dataMap[shape] else { const instance = new Shape(shape) dataMap[shape] = instance return instance } } } })() // test const rect = ShapeFactory.getShapeContext('rect'); const circle = ShapeFactory.getShapeContext('circle'); rect.draw(); // 画了一个 rect circle.draw(); // 画了一个 circle
适配器模式
/** * 适配器模式 */ const baiduMap = { show: function () { console.log('开始渲染百度地图') } } const AMap = { show: function () { console.log('开始渲染高德地图') } } /* 适配器 */ const baiduAdapter = { render: function () { return baiduMap.show() } } function renderMap(map) { if (typeof map.render === 'function') { map.render() } } // test renderMap(AMap); // 开始渲染高德地图 renderMap(baiduAdapter); // 开始渲染百度地图
装饰器模式
/** * 装饰器模式 */ const btn = document.querySelector('#btn') // 原绑定事件 btn.onclick = function () { console.log('按钮被点击了') } // 新增统计 function ajaxToServer() { console.log('数据统计') } // 装饰器函数 function decorator(target, eventName, cb) { const originFn = target['on' + eventName] originFn && originFn() cb && cb () } // test decorator(btn, 'click', ajaxToServer)
外观模式
/** * 外观模式 */ // 事件绑定 function addEvent(element, type, fn) { if (element.addEventListener) { element.addEventListener(type, fn, false) } else if (element.attachEvent) { element.attachEvent('on' + type, fn) } else { element['on' + type] = fn } } // 阻止事件冒泡 function cancelBubble(event) { if (event.stopPropagation) { event.stopPropagation() } else { event.cancelBubble = true } } // axios 中 getDefaultAdapter function getDefaultAdapter() { var baiduAdapter if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') { adapter = 'a' } else if (typeof XMLHttpRequest !== 'undefined') { adapter ='b' } return adapter }
组合模式
/** * 组合模式 */ // 创建部门 function createApartment(name) { return { name, _children: [], add(target) { this._children.push(target) return this }, show(cb) { this._children.forEach(function(child) { child.show(cb) }) } } } // 创建员工 function createEmp(num, name) { return { num, name, show(cb) { cb(this) } } } // 创建部门 const techApartment = createApartment('技术部') // 创建子部门 const proApartment = createApartment('产品组'), devApartment = createApartment('开发组') techApartment.add(proApartment).add(devApartment) proApartment.add(createEmp(100, '张三')) .add(createEmp(101, '李四')) techApartment.add(createEmp(201, '小刘')) .add(createEmp(202, '小王')) .add(createEmp(203, '小陈')) .add(createEmp(204, '小亮')) // 遍历 techApartment.show(function (item) { console.log(`工号:${item.num},姓名:${item.name}`) })
桥接模式
/** * 桥接模式 */ // 桥接方法 function addEvent(ele, eventName, fn) { document.querySelector(ele).addEventListener(eventName, fn, false) } // 具体业务 addEvent('#btn', 'click', function () { console.log('hello world') })
发布-订阅模式
// 事件监听器 const Emitter = (function () { const _events = {} return { // 事件绑定 on(type, cb) { if (!_events[type]) { _events[type] = [] } if (typeof cb === 'function') { _events[type].push(cb) } else { throw new Error('参数类型必须为函数') } }, // 事件解绑 off(type, cb) { if (!_events[type] || !_events[type].includes(cb)) return // 移除事件监听 _events[type].map((fn, index) => { if (fn == cb) { _events[type].splice(index, 1) } }) }, emit(type, ...args) { if (!_events[type]) return _events[type].forEach(cb => cb(...args)) } } })() // 事件订阅 Emitter.on('change', data => console.log(`我是第一条信息:${data}`)) Emitter.on('change', data => console.log(`我是第二条信息:${data}`)) // 事件发布 Emitter.emit('change', '参数')
发布-订阅模式和观察者模式相近,具体区别有:
策略模式
/** * 策略模式 */ // 校验规则 const strategyMap = { // 校验手机号 isMobile(mobile) { return /^1\d{10}$/.test(mobile) }, // 校验是否必填 isRequired(str) { return str.replace(/(^\s*)|(\s*$)/g, '') !== '' } } // 校验方法 function validate(formData) { let valid for (let key in formData) { const val = formData[key]?.value const rules = formData[key]?.rules for (let i = 0; i < rules.length; i++) { const result = strategyMap[rules[i]['rule'].call(null,val)] if (!result) { valid = { errField: key, errValue: value, errMsg: rules[i]['message'] } break } } if (valid) return valid } return valid } // form 表单校验 const formData = { mobile: { value: '1380000000', rules: [ { rule: 'isRequired', message: '手机号码不能为空' }, { rule: 'isMobile', message: '手机号码格式不正确' } ] } } // 获取校验结果 const valid = validate(formData) if (!valid) { console.log('校验通过') } else { console.log(valid) }
状态模式
/** * 状态模式 */ // 正常状态 function NormalState() { this.handleChange = function (context) { console.log('正常状态') context.state = new ColorfulState() } } // 彩灯状态 function ColorfulState() { this.handleChange = function (context) { console.log('彩灯状态') context.state = new CloseState() } } // 关闭状态 function CloseState() { this.handleChange = function (context) { console.log('关闭状态') context.state = new NormalState() } } // 灯 function Light(state) { this.state = state this.switch = function () { this.state.handleChange(this) } } // 设置灯光初始为关闭 const light = new Light(new CloseState()) // 关闭状态-->正常状态-->彩灯状态-->关闭状态... setInterval(() => { light.switch() }, 1000)
命令模式
/** * 命令模式 */ const Manager = (function () { // 命令 const commander = { open: function () { console.log('打开电视') }, close: function () { console.log('关闭电视') }, change: function (channel) { console.log('更换频道' + channel) } } return { // 执行命令 exec: function (cmd) { const args = [].splice.call(arguments, 1) commander[cmd] && commander[cmd][args] } } }) // test Manager.exec('open') // 打开电视 Manager.exec('change', 10) // 更换频道 10 Manager.exec('close') // 关闭电视
评论区