JavaScript常见的设计模式

94 阅读5分钟

工厂模式

顾名思义,工厂模式就是 创建一个工厂(类)来实例化对象,将实例化过程封在工厂类中,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象

class Byd {
   constructor(name) {
      this.name=name
   }
}

class Tsl {
   constructor(name) {
      this.name=name
   }
}

class Creator {
   create(name) {
      switch(name) {
       case "Byd"
          return new Byd(name)
       case "Tsl"
          return new Tsl(name)
      }
   }
}
const creator = new Creator();
const car = creator.create("Tsl");

单例模式

就是全局就一个实例,模块通常就是可做单例模式,还有一般使用闭包来做单例模式

class Win {
  constructor() {
     this.show = false
  }
  show() {
    this.show = true;
  }
  hide() {
    this.show= false;
  }
}
getInstance = (()=>{
  let globalWin=null;
  return  ()=>{
    if (!globalWin) {
      globalWin=new Win();
    }
    return globalWin
  }
})();
let win = getInstance();
let win2 = getInstance();
console.log(win==win2)

适配器模式

就是将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作

class Log {
   log(name) {
    console.log(name)
  }
}
class LLog {
   show(name) {
     console.log(name)
   }
}

class LLogAdapter {
   constructor(llog) {
     this.llog = llog
   }
   log(name) {
      return this.llog.show(name)
   }
}
log=new LLogAdapter(new LLog());
log.log("hello world")

装饰器模式

允许向一个现有的对象添加新的功能,同时又不改变其结构。装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能

class  Log{
   log(name) {
     console.log(name)
   }
}
class LogDecorator {
    constructor(logObj) {
       this.logObj = logObj
    }
    log(name) {
      const date = new Date();
      const now = date.getFullYear()+"-"+date.getMonth()+"-"+date.getDate();
      this.logObj.log(now+":"+name)
    }
}
const log = new LogDecorator(new Log());
log.log("hello,world")

代理模式

给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介

 class My {
   byHouse() {
     console.log("买房");
   }
 }
 class HouseProxy {
   constructor(obj) {
      this.obj = obj
   }
   byHouse() {
     console.log("选房");
     this.obj.byHouse();
   }
 }
const proxy = new HouseProxy(new My());
proxy.byHouse();

策略模式

定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码

const Utils= {
   isEmail(text) {
      return /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(text);
   },
   isIphone(text) {
     return /^1[3456789]\d{9}$/.test(text);
   }
}
class Validation {
   constructor(name) {
   this.checkType = name;
   }
   setCheckType(name) {
     this.checkType = name;
   }
   validate(text) {
     switch(this.checkType) {
       case "email":
       return Utils.isEmail(text);
       case "iphone":
       return Utils.isIphone(text);
     }
   }
}
const validate = new Validation('email');
validate.validate("10@qq.com");
validate.setCheckType("iphone")
validate.validate("13333333333");

状态模式

类的行为是基于它的状态改变的

class State {
  constructor(name) {
    this.name = name;
  } // 定义状态方法
  enter() {}
  exit() {}
  update() {}
} // 定义具体状态类
class IdleState extends State {
  constructor() {
    super("idle");
  }
  enter() {
    console.log("进入空闲状态");
  }
  exit() {
    console.log("离开空闲状态");
  }
  update() {
    console.log("空闲状态更新");
  }
}
class RunningState extends State {
  constructor() {
    super("running");
  }
  enter() {
    console.log("进入运行状态");
  }
  exit() {
    console.log("离开运行状态");
  }
  update() {
    console.log("运行状态更新");
  }
}
// 定义状态机类
class StateMachine {
  constructor() {
    this.states = {};
    this.currentState = null;
  }
  // 添加状态
  addState(state) {
    this.states[state.name] = state;
  } // 设置初始状态
  setState(stateName) {
    const state = this.states[stateName];
    if (state) {
      if (this.currentState) {
        this.currentState.exit();
      }
      this.currentState = state;
      this.currentState.enter();
    }
  }
  // 更新状态
  update() {
    if (this.currentState) {
      this.currentState.update();
    }
  }
}
// 使用示例
const stateMachine = new StateMachine();
const idleState = new IdleState();
const runningState = new RunningState();
stateMachine.addState(idleState);
stateMachine.addState(runningState);
stateMachine.setState("idle");
stateMachine.update();
stateMachine.setState("running");
stateMachine.update();


观察者模式

当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。当对象间存在一对多关系时,则使用观察者模式,比如,当一个对象被修改时,则会自动通知依赖它的对象.

观察者模式可以用于以下情况:

  1. 当一个对象的状态发生改变时,需要通知其他对象时,可以使用观察者模式。
  2. 当一个对象的状态有多个依赖者时,可以使用观察者模式。
  3. 当一个对象的状态发生改变时,需要执行一系列的操作时,可以使用观察者模式。

观察者模式的好处包括:

  1. 松耦合:观察者模式将观察者和被观察者分离开来,使得它们可以独立地变化,从而降低了它们之间的耦合度。
  2. 可扩展性:观察者模式使得添加新的观察者变得非常容易,只需要实现Observer接口即可。
  3. 可重用性:观察者模式可以在不同的被观察者之间共享观察者,从而提高了代码的可重用性。
  4. 灵活性:观察者模式允许在运行时动态地添加和删除观察者,从而提高了代码的灵活性。
  5. 易于维护:观察者模式将观察者和被观察者分离开来,从而使得代码更加易于维护。
 class Sub { 
  constructor () {
    this.observers= [];
  }
  add(observer) {
    this.observers.push(observer)
  }
  setSate(val) {
    this.state = val;
    this.notify();
  }
  notify() {
    for (const ob of this.observers) {
      ob.update();
    }
  }
}

class Observer {
  constructor(sub) {
    this.sub = sub;
    this.sub.add(this);
  }
  update() {
    console.log("更新了",this.sub.state)
  }
}
const obj = new Sub();
const ob1= new Observer(obj);
const ob2 = new Observer(obj);
obj.setSate(200);

迭代器模式

用于顺序访问集合对象的元素,不需要知道集合对象的底层表示

迭代器模式可以用于以下情况:

  1. 当你需要访问一个聚合对象的元素,但是不想暴露其内部表示时,可以使用迭代器模式。
  2. 当你需要为不同类型的聚合对象提供一致的迭代接口时,可以使用迭代器模式。
  3. 当你需要对聚合对象进行多次遍历时,可以使用迭代器模式。

迭代器模式的好处包括:

  1. 简化了聚合对象的代码,因为它不需要实现自己的迭代代码。
  2. 使得聚合对象的代码更加通用,因为它可以使用相同的迭代接口。
  3. 使得客户端代码更加简单,因为它只需要使用相同的迭代器接口来访问不同的聚合对象。
  4. 提高了代码的可维护性,因为它将遍历算法与聚合对象的表示分离开来,使得它们可以独立地变化。
class Iterator {
    constructor(val) {
        this.val = val;
        this.index=0;
    } 
    next() {
        if (this.index<this.val.length) {
            this.index++;
            return {value: this.val[this.index-1], done:false}
        } else {
            return {value: undefined, done: true}
        }
    }
}
class ArrayList {
   constructor(list) {
    this.list = list;
   }
   iterator() {
     return new Iterator(this.list);
   }
}
const arr = new ArrayList([1,2,3]);
const iter = arr.iterator();
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())