亲宝软件园·资讯

展开

javascript设计模式总结

前端喜哥 人气:0

一、设计模式介绍

什么是设计模式

设计模式的五大设计原则

设计模式的三大类

二、设计模式

1.工厂模式

优点

缺点

例子

class DownJacket {
  production(){
    console.log('生产羽绒服')
  }
}
class Underwear{
  production(){
    console.log('生产内衣')
  }
}
class TShirt{
  production(){
    console.log('生产t恤')
  }
}
// 工厂类
class clothingFactory {
  constructor(){
    this.downJacket = DownJacket
    this.underwear = Underwear
    this.t_shirt = TShirt
  }
  getFactory(clothingType){
    const _production = new this[clothingType]
    return _production.production()
  }
}
const clothing = new clothingFactory()
clothing.getFactory('t_shirt')// 生产t恤

2.抽象工厂模式

优点

缺点

例子

/* 抽象类
js中abstract是个保留字,实现抽象类只能通过new.target进行验证,
防止抽象类被直接实例,另外如果子类没有覆盖指定方法,则抛出错误
*/
class ProductionFlow {
  constructor(){
    if(new.target === ProductionFlow){
      throw new Error('抽象类不能被实例')
    }
  }
  production(){
    throw new Error('production要被重写')
  }
  materials(){
    throw new Error('materials要被重写')
  }
}
class DownJacket extends ProductionFlow{
  production(){
    console.log(`材料:${this.materials()},生产羽绒服`)
  }
  materials(){
    return '鸭毛'
  }
}
class Underwear extends ProductionFlow{
  production(){
    console.log(`材料:${this.materials()},生产内衣`)
  }
  materials(){
    return '丝光棉'
  }
}
class TShirt extends ProductionFlow{
  production(){
    console.log(`材料:${this.materials()},生产t恤`)
  }
  materials(){
    return '纯棉'
  }
}
function getAbstractProductionFactory(clothingType){
  const clothingObj = {
    downJacket:DownJacket,
    underwear:Underwear,
    t_shirt:TShirt,
  }
  if(clothingObj[clothingType]){
    return clothingObj[clothingType]
  }
  throw new Error(`工厂暂时不支持生产这个${clothingType}类型的服装`)
}
const downJacketClass = getAbstractProductionFactory('downJacket')
const underwearClass = getAbstractProductionFactory('underwear')
const downJacket = new downJacketClass()
const underwear = new underwearClass()
downJacket.production() // 材料:鸭毛,生产羽绒服
underwear.production() // 材料:丝光棉,生产内衣

3.建造者模式

优点

缺点

例子

下面继续用服装厂的生产流程作为例子。

// 抽象类
class Clothing {
  constructor() {
    this.clothingType = ''
    this.price
  }
}
class Underwear extends Clothing {
  constructor() {
    super()
    this.clothingType = 'underwear'
    this.price = 10
  }
}
class TShirt extends Clothing {
  constructor() {
    super()
    this.clothingType = 't_shirt'
    this.price = 50
  }
}
class DownCoat extends Clothing {
  constructor() {
    super()
    this.clothingType = 'DownCoat'
    this.price = 500
  }
}
// 产品
class Purchase {
  constructor() {
    this.clothings = []
  }
  addClothing(clothing) {
    this.clothings.push(clothing)
  }
  countPrice() {
    return this.clothings.reduce((prev, cur)=>cur.price + prev,0)
  }
}
// 厂长
class FactoryManager {
  createUnderwear() {
    throw new Error(`子类必须重写 createUnderwear`)
  }
  createTShirt() {
    throw new Error(`子类必须重写 createTShirt`)
  }
  createDownCoat() {
    throw new Error(`子类必须重写 DownCoat`)
  }
}
// 工人
class Worker extends FactoryManager {
  constructor() {
    super()
    this.purchase = new Purchase()
  }
  createUnderwear(num) {
    for (let i = 0; i < num; i++) {
      this.purchase.addClothing(new Underwear())
    }
  }
  createTShirt(num) {
    for (let i = 0; i < num; i++) {
      this.purchase.addClothing(new TShirt())
    }
  }
  createDownCoat(num) {
    for (let i = 0; i < num; i++) {
      this.purchase.addClothing(new DownCoat())
    }
  }
}
// 销售
class Salesman {
  constructor() {
    this.worker = null
  }
  setWorker(worker) {
    this.worker = worker
  }
  reserve(clothing) {
    clothing.forEach((item) => {
      if (item.type === 'underwear') {
        this.worker.createUnderwear(item.num)
      } else if (item.type === 't_shirt') {
        this.worker.createTShirt(item.num)
      } else if (item.type === 'DownCoat') {
        this.worker.createDownCoat(item.num)
      } else {
        try {
          throw new Error('公司暂不生产或不存在该类型的商品')
        } catch (error) {
          console.log(error)
        }
      }
    });
    const purchase = this.worker.purchase
    return purchase.countPrice()
  }
}
const salesman = new Salesman()
const worker = new Worker()
salesman.setWorker(worker)
const order = [
  {
    type: 'underwear',
    num: 10
  },
  {
    type: 't_shirt',
    num: 4
  },
  {
    type: 'DownCoat',
    num: 1
  }
]
console.log(`本次订单所需金额:${salesman.reserve(order)}`)

4.单例模式

优点

缺点

例子

class LoginFrame {
    static instance = null
    constructor(state){
        this.state = state
    }
    show(){
        if(this.state === 'show'){
            console.log('登录框已显示')
            return
        }
        this.state = 'show'
        console.log('登录框展示成功')
    }
    hide(){
        if(this.state === 'hide'){
            console.log('登录框已隐藏')
            return
        }
        this.state = 'hide'
        console.log('登录框隐藏成功')
    }
    // 通过静态方法获取静态属性instance上是否存在实例,如果没有创建一个并返回,反之直接返回已有的实例
    static getInstance(state){
        if(!this.instance){
            this.instance = new LoginFrame(state)
        }
        return this.instance
    }
}
const p1 = LoginFrame.getInstance('show')
const p2 = LoginFrame.getInstance('hide')
console.log(p1 === p2) // true

5.适配器模式

优点

缺点

例子

class Jack {
  english() {
    return 'I speak English'
  }
}
class Xiaoming {
  chinese() {
    return '我只会中文'
  }
}
// 适配器
class XiaoHong {
  constructor(person) {
    this.person = person
  }
  chinese() {
    return `${this.person.english()} 翻译: "我会说英语"`
  }
}
class Communication {
  speak(language) {
    console.log(language.chinese())
  }
}
const xiaoming = new Xiaoming()
const xiaoHong = new XiaoHong(new Jack())
const communication = new Communication()
communication.speak(xiaoming)
communication.speak(xiaoHong)

6.装饰器模式

优点

缺点

例子

class Aircraft {
    ordinary(){
        console.log('发射普通子弹')
    }
}
class AircraftDecorator {
    constructor(aircraft){
        this.aircraft = aircraft
    }
    laser(){
        console.log('发射激光')
    }
    guidedMissile(){
        console.log('发射导弹')
    }
    ordinary(){
        this.aircraft.ordinary()
    }
}
const aircraft = new Aircraft()
const aircraftDecorator = new AircraftDecorator(aircraft)
aircraftDecorator.ordinary() // 发射普通子弹
aircraftDecorator.laser() // 发射激光
aircraftDecorator.guidedMissile() // 发射导弹
// 可以看到在不更改源代码的情况下对它进行了装饰扩展

7.代理模式

优点

缺点

例子

// 员工
class Staff {
  constructor(affairType){
    this.affairType = affairType
  }
  applyFor(target){
    target.receiveApplyFor(this.affairType)
  }
}
// 秘书
class Secretary {
  constructor(){
    this.leader = new Leader()
  }
  receiveApplyFor(affair){
    this.leader.receiveApplyFor(affair)
  }
}
//领导
class Leader {
  receiveApplyFor(affair){
    console.log(`批准:${affair}`)
  }
}
const staff = new Staff('升职加薪')
staff.applyFor(new Secretary()) // 批准:升职加薪

8.外观模式

优点

缺点

例子

function addEvent(el,type,fn){
    if(el.addEventlistener){// 高级游览器添加事件DOM API
        el.addEventlistener(type,fn,false)
    }else if(el.attachEvent){// 低版本游览器的添加事件API
        el.attachEvent(`on${type}`,fn)
    }else {//其他
        el[type] = fn
    }
}
function bindEvent(el,type,selector,fn){
    if(!fn){
        fn = selector
    }
    // 其他代码
    console.log(el,type,fn)
}
bindEvent(document.body,'click','#root',()=>{})
bindEvent(document.body,'click',()=>{})

9.发布订阅模式

优点

缺点

例子

class Subject {
  constructor(){
    this.observers = {}
    this.key = ''
  }
  add(observer){
    const key = observer.project
    if (!this.observers[key]) {
      this.observers[key] = []
    }
    this.observers[key].push(observer)
  }
  remove(observer){
    const _observers = this.observers[observer.project]
    console.log(_observers,11)
    if(_observers.length){
      _observers.forEach((item,index)=&gt;{
        if(item === observer){
          _observers.splice(index,1)
        }
      })
    }
  }
  setObserver(subject){
    this.key = subject
    this.notifyAllObservers()
  }
  notifyAllObservers(){
    this.observers[this.key].forEach((item,index)=&gt;{
      item.update()
    })
  }
}
class Observer {
  constructor(project,name) {
    this.project = project
    this.name = name
  }
  update() {
    console.log(`尊敬的:${this.name} 你预约的项目:【${this.project}】 马上开始了`)
  }
}
const subject = new Subject()
const xiaoming = new Observer('滑雪','xiaoming')
const A = new Observer('大跳台','A')
const B = new Observer('大跳台','B')
const C = new Observer('大跳台','C')
subject.add(xiaoming)
subject.add(A)
subject.add(B)
subject.add(C)
subject.remove(B) // 取消订阅
subject.setObserver('大跳台')
/** 执行结果
 * 尊敬的:A 你预约的项目:【大跳台】 马上开始了
 * 尊敬的:C 你预约的项目:【大跳台】 马上开始了
 */

10.迭代器模式

优点

缺点

例子

迭代器分为内部迭代器和外部迭代器,它们有各自的适用场景。

// 内部迭代器表示内部已经定义好了迭代规则,它完全接受整个迭代过程,外部只需一次初始调用。
Array.prototype.MyEach = function(fn){
    for(let i = 0;i<this.length;i++){
        fn(this[i],i,this)
    }
}
Array.prototype.MyEach = function(fn){
    for(let i = 0;i<this.length;i++){
        fn(this[i],i,this)
    }
}
[1,2,3,4].MyEach((item,index)=>{
    console.log(item,index)
})
// 外部迭代器必须显示的迭代下一个元素。它增加了调用的复杂度,但也增加了迭代器的灵活性,可以手动控制迭代的过程。
class Iterator{
    constructor(arr){
        this.current = 0
        this.length = arr.length
        this.arr = arr
    }
    next(){
        return this.getCurrItem()
    }
    isDone(){
        return this.current>=this.length
    }
    getCurrItem(){
        return {
            done:this.isDone(),
            value:this.arr[this.current++]
        }
    }
}
let iterator =new Iterator([1,2,3])
while(!(item=iterator.next()).done) { 
    console.log(item) 
}
iterator.next()
/* 下面的数据格式是不是有点熟悉
{done: false, value: 1}
{done: false, value: 2}
{done: false, value: 3}
{done: true, value: undefined}
*/

11.状态模式

优点

缺点

例子

class State {
  constructor(attack){
    this.attack = attack
  }
  handle(context){
    console.log(this.attack)
    context.setState(this)
  }
}
class Context {
  constructor(){
    this.state = null
  }
  getState(){
    return this.state
  }
  setState(state){
    this.state = state
  }
}
const q1 = new State('q1 第1击'),
      q2 = new State('q2 第2击'),
      q3 = new State('q3 第3击'),
      context = new Context()
q1.handle(context)//q1 第1击
q2.handle(context)//q2 第2击
q3.handle(context)//q3 第3击

12.策略模式

优点

缺点

例子

const rules = {
    cover_img: {
        must: false,
        msg: '请上传封面图片',
        val: ''
    },
    name: {
        must: true,
        msg: '姓名不能为空',
        val: ''
    },
    sex: {
        must: true,
        msg: '请填写性别',
        val: ''
    },
    birthday: {
        must: false,
        msg: '请选择生日',
        val: ''
    },
}
function verify(){
    for(const key in rules){
        if(rules[key].must&amp;&amp;!rules[key].val){
            console.log(rules[key].msg)
        }
    }
}
verify()
// 姓名不能为空
// 请填写性别
//html-----------------
<form action="http:// xxx.com/register" id="registerForm" method="post">
    请输入用户名:<input type="text" name="userName" />
    请输入密码:<input type="text" name="password" />
    请输入手机号码:<input type="text" name="phoneNumber" />
    <button>提交</button>
</form>
// js------------------
class Strategies {
  constructor() {
    this.rules = {}
  }
  add(key, rule) {
    this.rules[key] = rule
    return this
  }
}
class Validator {
  constructor(strategies) {
    this.cache = [] // 保存检验规则
    this.strategies = strategies
  }
  add(dom, rules) {
    rules.forEach((rule) => {
      const strategyAry = rule.strategy.split(':')
      this.cache.push(() => {
        const strategy = strategyAry.shift()
        strategyAry.unshift(dom.value)
        strategyAry.push(rule.errorMsg)
        console.log(this.strategies[strategy])
        return this.strategies[strategy].apply(dom, strategyAry)
      })
    });
  }
  start() {
    for (let i = 0,validatorFunc; validatorFunc =this.cache[i++]; ) {
      const msg = validatorFunc()
      if (msg) {
        return msg
      }
    }
  }
}
const registerForm = document.getElementById('registerForm') // 获取formDom节点
const strategies = new Strategies()
strategies.add('isNonEmpty', function(value, errorMsg) {
  if (!value) {
    return errorMsg
  }
}).add('minLength', function(value, length, errorMsg) {
  if (value.length < length) {
    return errorMsg
  }
}).add('isMobile', function(value, errorMsg) {
  if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
    return errorMsg
  }
})
function validataFunc() {
  const validator = new Validator(strategies.rules)
  // 多个校验规则
  validator.add(registerForm.userName, [
    {
      strategy: 'isNonEmpty',
      errorMsg: '用户名不能为空'
    }, {
      strategy: 'minLength:10',
      errorMsg: '用户名长度不能少于10位'
    }
  ])
  validator.add(registerForm.password, [{
    strategy: 'minLength:6',
    errorMsg: '密码长度不能少于6位'
  }])
  validator.add(registerForm.phoneNumber, [{
    strategy: 'isMobile',
    errorMsg: '手机号码格式不对'
  }])
  const errorMsg = validator.start()
  return errorMsg // 返回错误信息。
}
registerForm.onsubmit = function () {
  const errorMsg = validataFunc()
  if (errorMsg) { // 如果存在错误信息,显示错误信息,并且阻止onsubmit默认事件
    console.log(errorMsg)
    return false
  }
}

13.命令模式

优点

缺点

例子

// html-------------------
<button id="button2">点击按钮 1</button>
<button id="button2">点击按钮 2</button>
<button id="button3">点击按钮 3</button>
// js---------------------
const button1 = document.getElementById('button1'),
  button2 = document.getElementById('button2'),
  button3 = document.getElementById('button3');
  const MenBar = {
    refresh:function(){
      console.log('刷新菜单目录')
    }
  }
  const SubMenu = {
    add:function(){
      console.log('增加子菜单')
    },
    del:function(){
      console.log('删除子菜单')
    }
  }
  function setCommand(el,command){
    el.onclick = function(){
      command.execute()
    }
  }
  class MenuBarCommand{
    constructor(receiver,key){
      this.receiver = receiver
      this.key = key
    }
    execute(){
      this.receiver[this.key]()
    }
  }
  setCommand(button1,new MenuBarCommand(MenBar,'refresh'))
  setCommand(button2,new MenuBarCommand(SubMenu,'add'))
  setCommand(button3,new MenuBarCommand(SubMenu,'del'))

14.组合模式

优点

缺点

例子

// 文件夹类
class Folder {
  constructor(name) {
    this.name = name
    this.parent = null;
    this.files = []
  }
  // 添加文件
  add(file) {
    file.parent = this
    this.files.push(file)
    return this
  }
  // 扫描文件
  scan() {
    console.log(`开始扫描文件夹:${this.name}`)
    this.files.forEach(file =&gt; {
      file.scan()
    });
  }
  // 删除指定文件
  remove() {
    if (!this.parent) {
      return
    }
    for (let files = this.parent.files, i = files.length - 1; i &gt;= 0; i--) {
      const file = files[i]
      if (file === this) {
        files.splice(i, 1)
        break
      }
    }
  }
}
// 文件类
class File {
  constructor(name) {
    this.name = name
    this.parent = null
  }
  add() {
    throw new Error('文件下面不能添加任何文件')
  }
  scan() {
    console.log(`开始扫描文件:${this.name}`)
  }
  remove() {
    if (!this.parent) {
      return
    }
    for (let files = this.parent.files, i = files.length - 1; i &gt;= 0; i++) {
      const file = files[i]
      if (file === this) {
        files.splice(i, 1)
      }
    }
  }
}
const book = new Folder('电子书')
const js = new Folder('js')
const node = new Folder('node')
const vue = new Folder('vue')
const js_file1 = new File('javascript高级程序设计')
const js_file2 = new File('javascript忍者秘籍')
const node_file1 = new File('nodejs深入浅出')
const vue_file1 = new File('vue深入浅出')
const designMode = new File('javascript设计模式实战')
js.add(js_file1).add(js_file2)
node.add(node_file1)
vue.add(vue_file1)
book.add(js).add(node).add(vue).add(designMode)
book.remove()
book.scan()

15.模块方法模式

优点

缺点

例子

// 抽象父类
class Beverage {
  boilWater(){
    console.log('把水煮沸')
  }
  brew(){
    throw new Error('字类必须重写brew方法')
  }
  pourInCup(){
    throw new Error('字类必须重写pourInCup方法')
  }
  addCondiments(){
    throw new Error('字类必须重写addCondiments方法')
  }
  init(){
    this.boilWater()
    this.brew()
    this.pourInCup()
    this.addCondiments()
  }
}
// 咖啡类
class Coffee extends Beverage {
  brew(){
    console.log('用沸水冲泡咖啡')
  }
  pourInCup(){
    console.log('把咖啡倒进杯子')
  }
  addCondiments(){
    console.log('加糖和牛奶')
  }
}
// 茶类
class Tea extends Beverage {
  brew(){
    console.log('用沸水侵泡茶叶')
  }
  pourInCup(){
    console.log('把茶倒进杯子')
  }
  addCondiments(){
    console.log('加柠檬')
  }
}
const coffee = new Coffee()
coffee.init()
const tea = new Tea()
tea.init()

16.享元模式

优点

缺点

例子

let id = 0
// 定义内部状态
class Upload {
  constructor(uploadType) {
    this.uploadType = uploadType
  }
  // 点击删除时 小于3000直接删除,大于3000通过confirm提示弹窗删除。
  delFile(id) {
    uploadManager.setExternalState(id,this)
    if(this.fileSize &lt; 3000){
      return this.dom.parentNode.removeChild(this.dom)
    }
    if(window.confirm(`确定要删除该文件吗?${this.fileName}`)){
      return this.dom.parentNode.removeChild(this.dom)
    }
  }
}
// 外部状态
class uploadManager {
  static uploadDatabase = {}
  static add(id, uploadType, fileName, fileSize) {
    const filWeightObj = UploadFactory.create(uploadType)
    const dom = this.createDom(fileName, fileSize, () =&gt; {
      filWeightObj.delFile(id)
    })
    this.uploadDatabase[id] = {
      fileName,
      fileSize,
      dom
    }
  }
  // 创建DOM 并且为button绑定删除事件。
  static createDom(fileName, fileSize, fn) {
    const dom = document.createElement('div')
    dom.innerHTML = `
      &lt;span&gt;文件名称:${fileName},文件大小:${fileSize}&lt;/span&gt;
      &lt;button class="delFile"&gt;删除&lt;/button&gt;
    `
    dom.querySelector('.delFile').onclick = fn
    document.body.append(dom)
    return dom
  }
  static setExternalState(id, flyWeightObj) {
    const uploadData = this.uploadDatabase[id]
    for (const key in uploadData) {
      if (Object.hasOwnProperty.call(uploadData, key)) {
        flyWeightObj[key] = uploadData[key]
      }
    }
  }
}
// 定义一个工厂创建upload对象,如果其内部状态实例对象存在直接返回,反之创建保存并返回。
class UploadFactory {
  static createFlyWeightObjs = {}
  static create(uploadType) {
    if (this.createFlyWeightObjs[uploadType]) {
      return this.createFlyWeightObjs[uploadType]
    }
    return this.createFlyWeightObjs[uploadType] = new Upload(uploadType)
  }
}
// 开始加载
const startUpload = (uploadType, files)=&gt;{
    for (let i = 0, file; file = files[i++];) {
      uploadManager.add(++id, uploadType, file.fileName, file.fileSize)
    }
}
startUpload('plugin', [
  {fileName: '1.txt',fileSize: 1000},
  {fileName: '2.html',fileSize: 3000},
  {fileName: '3.txt',fileSize: 5000}
]);
startUpload('flash', [
  {fileName: '4.txt',fileSize: 1000},
  {fileName: '5.html',fileSize: 3000},
  {fileName: '6.txt',fileSize: 5000}
]);

17.职责链模式

优点

缺点

例子

class Order500 {
    constructor(){
        this.orderType = 1
    }
    handle(orderType, pay, stock){
        if(orderType === this.orderType&&pay){
            console.log('500元定金预约,得到100元优惠券')
        }else {
            return 'nextSuccessor'
        }
    }
}
class Order200 {
    constructor(){
        this.orderType = 2
    }
    handle(orderType, pay, stock){
        if(orderType === this.orderType&&pay){
            console.log('200元订金预约,得到50元优惠卷')
        }else {
            return 'nextSuccessor'
        }
    }
}
class OrderNormal {
    constructor(){
        this.stock = 0
    }
    handle(orderType, pay, stock){
        if (stock > this.stock) {
            console.log('普通购买,无优惠卷')
          } else {
            console.log('手机库存不足')
          }
    }
}
class Chain {
  constructor(order){
    this.order = order
    this.successor = null
  }
  setNextSuccessor(successor){
    return this.successor = successor
  }
  passRequest(...val){
    const ret = this.order.handle.apply(this.order,val)
    if(ret === 'nextSuccessor'){
      return this.successor&&this.successor.passRequest.apply(this.successor,val)
    }
    return ret
  }
}
console.log(new Order500())
var chainOrder500 = new Chain( new Order500() );
var chainOrder200 = new Chain( new Order200() );
var chainOrderNormal = new Chain( new OrderNormal() );
chainOrder500.setNextSuccessor( chainOrder200 );
chainOrder200.setNextSuccessor( chainOrderNormal );
chainOrder500.passRequest( 1, true, 500 ); // 输出:500 元定金预购,得到 100 优惠券
chainOrder500.passRequest( 2, true, 500 ); // 输出:200 元定金预购,得到 50 优惠券
chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足

18.中介模式

优点

缺点

例子

// html-----------
选择颜色:<select name="" id="colorSelect">
    <option value="">请选择</option>
    <option value="red">红色</option>
    <option value="blue">蓝色</option>
  </select>
  <br />
  选择内存:<select name="" id="memorySelect">
    <option value="">请选择</option>
    <option value="32G">32G</option>
    <option value="63G">64G</option>
  </select>
  <br />
  输入购买数量:<input type="text" id="numberInput" />
  <br />
  <div>你选择了颜色:<span id="colorInfo"></span></div>
  <div>你选择了内存:<span id="memoryInfo"></span></div>
  <div>你选择了数量:<span id="numberInfo"></span></div>
  <button id="nextBtn" disabled="true">请选择手机颜色和购买数量</button>
  // js -------------------
const goods = {
      "red|32G": 3,
      "red|16G": 0,
      "blue|32G": 1,
      "blue|16G": 6
    },
      colorSelect = document.getElementById('colorSelect'),
      memorySelect = document.getElementById('memorySelect'),
      numberInput = document.getElementById('numberInput'),
      colorInfo = document.getElementById('colorInfo'),
      memoryInfo = document.getElementById('memoryInfo'),
      numberInfo = document.getElementById('numberInfo'),
      nextBtn = document.getElementById('nextBtn'),
      mediator = (function () {
        return {
          changed(obj) {
            const color = colorSelect.value,
              memory = memorySelect.value,
              number = numberInput.value,
              stock = goods[`${color}|${memory}`]
            if (obj === colorSelect) {
              colorInfo.innerHTML = color
            } else if (obj === memorySelect) {
              memoryInfo.innerHTML = memory
            } else if (obj === numberInput) {
              numberInfo.innerHTML = number
            }
            if (!color) {
              nextBtn.disabled = true
              nextBtn.innerHTML = '请选择手机颜色'
              return
            }
            if (!memory) {
              nextBtn.disabled = true
              nextBtn.innerHTML = '请选择内存大小'
              return
            }
            if (Number.isInteger(number - 0) && number < 1) {
              nextBtn.disabled = true
              nextBtn.innerHTML = '请输入正确的购买数量'
              return
            }
            nextBtn.disabled = false
            nextBtn.innerHTML = '放入购物车'
          }
        }
      })()
    colorSelect.onchange = function () {
      mediator.changed(this)
    }
    memorySelect.onchange = function () {
      mediator.changed(this)
    }
    numberInput.oninput = function () {
      mediator.changed(this)
    }

19.原型模式

优点

缺点

例子

const user = {
    name:'小明',
    age:'30',
    getInfo(){
        console.log(`姓名:${this.name},年龄:${this.age}`)
    }
}
const xiaozhang = Object.create(user)
xiaozhang.name = '小张'
xiaozhang.age = 18
xiaozhang.getInfo() // 姓名:小张,年龄:18
user.getInfo() // 姓名:小明,年龄:30

20.备忘录模式

优点

缺点

例子

// 棋子
class ChessPieces {
  constructor(){
    this.chess = {}
  }
  // 获取棋子
  getChess(){
    return this.chess
  }
}
// 记录棋路
class Record {
  constructor(){
    this.chessTallyBook = [] // 记录棋路
  }
  recordTallyBook(chess){
    // console.log(this.chessTallyBook.includes(chess))
    const isLoadtion = this.chessTallyBook.some(
      item=>item.location === chess.location
    )
    if(isLoadtion){
      console.log(`${chess.type},${chess.location}已存在其他棋子`)
    }else {
      this.chessTallyBook.push(chess)
    }
    // this.chessTallyBook.some(item=>item.location === chess.location)
  }
  getTallyBook(){
    return this.chessTallyBook.pop()
  }
}
// 下棋规则
class ChessRule {
  constructor(){
    this.chessInfo = {}
  }
  playChess(chess){
    this.chessInfo = chess
  }
  getChess(){
    return this.chessInfo
  }
  // 记录棋路
  recordTallyBook(){
    return new ChessPieces(this.chessInfo)
  }
  // 悔棋
  repentanceChess(chess){
    this.chessInfo = chess.getTallyBook()
  }
}
const chessRule = new ChessRule()
const record = new Record()
chessRule.playChess({
  type:'黑棋',
  location:'X10,Y10'
})
record.recordTallyBook(chessRule.getChess())//记录棋路
chessRule.playChess({
  type:'白棋',
  location:'X11,Y10'
})
record.recordTallyBook(chessRule.getChess())//记录棋路
chessRule.playChess({
  type:'黑棋',
  location:'X11,Y11'
})
record.recordTallyBook(chessRule.getChess())//记录棋路
chessRule.playChess({
  type:'白棋',
  location:'X12,Y10'
})
console.log(chessRule.getChess())//{type:'白棋',location:'X12,Y10'}
chessRule.repentanceChess(record) // 悔棋
console.log(chessRule.getChess())//{type:'黑棋',location:'X11,Y11'}
chessRule.repentanceChess(record) // 悔棋
console.log(chessRule.getChess())//{type:'白棋',location:'X11,Y10'}

21.桥接模式

优点

缺点

例子

class Phone {
    constructor(brand,modle){
        this.brand = brand
        this.modle = modle
    }
    showPhone(){
        return `手机的品牌:${this.brand.getBrand()},型号${this.modle.getModle()}`
    }
}
class Brand {
    constructor(brandName){
        this.brandName = brandName
    }
    getBrand(){
        return this.brandName
    }
}
class Modle {
    constructor(modleName){
        this.modleName = modleName
    }
    getModle(){
        return this.modleName
    }
}
const phone = new Phone(new Brand('华为'),new Modle('mate 40'))
console.log(phone.showPhone())

22.访问者模式

优点

缺点

例子

    class Phone {
      accept() {
        throw new Error('子类的accept必须被重写')
      }
    }
    class Mata40Pro extends Phone {
      accept() {
        const phoneVisitor = new PhoneVisitor()
        return phoneVisitor.visit(this)
      }
    }
    class IPhone13 extends Phone {
      accept() {
        const phoneVisitor = new PhoneVisitor()
        return phoneVisitor.visit(this)
      }
    }
    // 访问者类
    class PhoneVisitor {
      visit(phone) {
        if (phone.constructor === IPhone13) {
          return {
            os: 'ios',
            chip: 'A15仿生芯片',
            screen: '电容屏'
          }
        } else if (phone.constructor === Mata40Pro) {
          return {
            os: 'HarmonyOS',
            chip: 'Kirin 9000',
            GPUType: 'Mali-G78',
            port: 'type-c'
          }
        }
      }
    }
    const mata40Pro = new Mata40Pro()
    console.log(mata40Pro.accept())

23.解释器模式

优点

缺点

例子

class TerminalExpression {
  constructor(data) {
    this.data = data
  }
  interpret(context) {
    if (context.indexOf(this.data) &gt; -1) {
      return true;
    }
    return false;
  }
}
class OrExpression {
  constructor(expr1, expr2) {
    this.expr1 = expr1;
    this.expr2 = expr2;
  }
  interpret(context) {
    return this.expr1.interpret(context) || this.expr2.interpret(context);
  }
}
class AndExpression {
  constructor(expr1, expr2) {
    this.expr1 = expr1;
    this.expr2 = expr2;
  }
  interpret(context) {
    return this.expr1.interpret(context) &amp;&amp; this.expr2.interpret(context);
  }
}
class InterpreterPatternDemo {
  static getMaleExpression() {
    const robert = new TerminalExpression("小明");
    const john = new TerminalExpression("小龙");
    return new OrExpression(robert, john);
  }
  static getMarriedWomanExpression() {
    const julie = new TerminalExpression("张三");
    const married = new TerminalExpression("小红");
    return new AndExpression(julie, married);
  }
  static init(args) {
    const isMale = this.getMaleExpression();
    const isMarriedWoman = this.getMarriedWomanExpression();
    console.log(`小龙是男性?${isMale.interpret("小龙")}`)
    console.log(`小红是一个已婚妇女?${isMarriedWoman.interpret("小红 张三")}`)
  }
}
InterpreterPatternDemo.init()

总结

加载全部内容

相关教程
猜你喜欢
用户评论