尼采般地抒情

尼采般地抒情

尼采般地抒情

音乐盒

站点信息

文章总数目: 318
已运行时间: 1825

一、单例模式

类只有一个实例,像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')       // 关闭电视

参考

评论区

什么都不舍弃,什么也改变不了