一、单例模式
类只有一个实例,像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') // 关闭电视
评论区