设计模式

1.单例模式
保证全局只有一个实例,节省资源,类似java的静态类 static,一般用到的地方有历史记录、线程池等等

let Singleton=function(){
  this.name=1
}
//因为javascript 没有静态类的标识 故用闭包保持唯一性 外部无法访问instance
Singleton.getInstance=(function(){
  let instance=null
  return function(){
    if(!instance ){
        instance=new Singleton()
    }
    return instance
  }
})()

let s1=Singleton.getInstance()
let s2=Singleton.getInstance()
console.log(s1===s2)//true
console.log(s1.name)//1
s1.name=2
console.log(s1.name)//2
console.log(s2.name)//2

2.策略类
比如算法,各种算法封装在策略类,各种方法的使用交给环境类
看代码:


let strategy={
  //冒泡排序 逐个调换位置
  A(numbers){
    for(let i=0;i<numbers.length;i++){
      for(let j=0;j<numbers.length;j++){
        let itemNext=numbers[j+1]
        let item=numbers[j]
        if(itemNext<item){
            numbers[j+1]=item
            numbers[j]=itemNext
        }
      }
    }
    return numbers
  },
  //选择排序 每次循环把最小的放入前置位
  B(numbers){
    for(let i=0;i<numbers.length;i++){
      let itemI=numbers[i]
      for(let j=i+1;j<numbers.length;j++){
        let itemJ=numbers[j]
        if(itemI>itemJ){
            numbers[i]=itemJ
            numbers[j]=itemI
            itemI=itemJ
        }
      }
    }
    return numbers
  }
}
let content=name=>{
  let numbers=[1,3,5,6,1,3,4,6,5]
  return strategy[name](numbers)
}
console.log(content('A'))
console.log(content('B'))

3.代理模式
高度解耦,对象保护,易修改,因为是代理,所以会慢一点
示例代码:

let myImg={
  setSrc(img,src){
    img.src=src
  }
}

let proxyImg={
  setImg(imgNode,src){
    //实现图片懒加载
    myImg.setSrc(imgNode,'默认图.png')//占位图片
    let img=new Image()
    imgNode.onLoad=function(){
      myImg.setSrc(imgNode,src)
    }
    img.src=src//真正要加载的产品图片
  }
}
let imgNode=document.crateElement('img')
let imgUrl='产品图.png'
document.body.append(imgUrl)

proxyImg.setImg(imgNode,imgUrl)

4.迭代器模式
迭代器模式是指提供一种方法顺序访问一个集合对象的各个元素,使用者不需要了解集合对象的底层实现。
不太清楚其用途~

let Iterator=obj=>{
  let current=0;
  let next = ()=>current+=1
  let end = ()=>current>=obj.length
  let get = ()=>obj[current]
  return{
    next,
    end,
    get
  }
}
let myIter = Iterator([1, 2, 3]);
while(!myIter.end()) { 
  console.log(myIter.get()) myIter.next(); 
}

5.订阅发布模式
订阅-发布模式定义了对象之间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都可以得到通知。

event.js
class Event{
  constructor(){
    this._cbs={}
  }
  //订阅
  on(key,fn){
    if(typeof fn != "function"){
      return false
    }
    this._cbs = this._cbs || {};
    (this._cbs[key] = this._cbs[key] || []).push(fn)
  }
  //发布
  emit(){
     let _cbs=this._cbs
     let key=Array.prototype.shift.apply(arguments)
     let affair =_cbs[key]||[]
     if(!affair||affair.length<1){
      return false
     }
     for(let fn of affair){
       fn.apply(null,arguments)
     }
     return true
  }
  //销毁
  off(key,fn){
    this._cbs = this._cbs || {}
    // all
    if (!arguments.length) {
      this._cbs = {}
      return true
    }
    var callbacks = this._cbs[key]
    if (!callbacks) return
    // remove all handlers
    if (arguments.length === 1) {
      delete this._cbs[key]
      return true
    }
 // remove specific handler
    var cb
    for (var i = 0, len = callbacks.length; i < len; i++) {
      cb = callbacks[i]
      if (cb === fn || cb.fn === fn) {
        callbacks.splice(i, 1)
        break
      }
    }
    return true
  }
}

export default Event
  //a.js
  import Event from event.js
  let e=new Event()
  e.on('one',v=>{
    console.log('订阅')
    console.log(v)
  })

   e.emit('one',1000)
   e.off('one')
   e.emit('one',1000)

6.工厂模式
工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。” 简单来说:就是把new对象的操作包裹一层,对外提供一个可以根据不同参数创建不同对象的函数。

class Dog{
  run(){
      console.log('狗')
  }
}

class Cat{
  run(){
      console.log('猫')
  }
}

class Animal{
  constructor(name){
    name = name.toLocaleLowerCase()
    switch(name){
      case 'cat':
        return new Dog()
      case 'dog':
        return new Cat()
      default:
        console.log('没有哦')
    }
  }
}

let ss=new Animal('cat')
ss.run()

7.组合模式
用小的子对象构造更大的父对象,而这些子对象也由更小的子对象构成 单个对象和组合对象对于用户暴露的接口具有一致性,而同种接口不同表现形式亦体现了多态性

// 文件类
class File {
  constructor(name) {
    this.name = name || "File";
  }

  add() {
    throw new Error("文件夹下面不能添加文件");
  }

  scan() {
    console.log("扫描文件: " + this.name);
  }
}

// 文件夹类
class Folder {
  constructor(name) {
    this.name = name || "Folder";
    this.files = [];
  }

  add(file) {
    this.files.push(file);
  }

  scan() {
    console.log("扫描文件夹: " + this.name);
    for (let file of this.files) {
      file.scan();
    }
  }
}

let home = new Folder("用户根目录");

let folder1 = new Folder("第一个文件夹"),
  folder2 = new Folder("第二个文件夹");

let file1 = new File("1号文件"),
  file2 = new File("2号文件"),
  file3 = new File("3号文件");

// 将文件添加到对应文件夹中
folder1.add(file1);

folder2.add(file2);
folder2.add(file3);

// 将文件夹添加到更高级的目录文件夹中
home.add(folder1);
home.add(folder2);

// 扫描目录文件夹
home.scan();

8.享元模式
享元模式:运用共享技术来减少创建对象的数量,从而减少内存占用、提高性能。

class ObjectPool{
  constructor(){
    this._pool=[]
  }
  create(obj){
    return this._pool.length===0?
    new obj(this):
    this._pool.shift()
  }
  recover(obj){
    return this._pool.push(obj);
  }
  // 对象池大小 
  size() { 
    return this._pool.length; 
  }
}

// 模拟文件对象
class File {
  constructor(pool) {
    this.pool = pool;
  }

  // 模拟下载操作
  download() {
    console.log(`+ 从 ${this.src} 开始下载 ${this.name}`);
    setTimeout(() => {
      console.log(`- ${this.name} 下载完毕`); // 下载完毕后, 将对象重新放入对象池
      this.pool.recover(this);
    }, 100);
  }
}

/****************** 以下是测试函数 **********************/

let objPool = new ObjectPool();

let file1 = objPool.create(File);
file1.name = "文件1";
file1.src = "https://download1.com";
file1.download();

let file2 = objPool.create(File);
file2.name = "文件2";
file2.src = "https://download2.com";
file2.download();

setTimeout(() => {
  let file3 = objPool.create(File);
  file3.name = "文件3";
  file3.src = "https://download3.com";
  file3.download();
}, 200);

setTimeout(
  () =>
    console.log(
      `${"*".repeat(50)}\n下载了3个文件,但其实只创建了${objPool.size()}个对象`
    ),
  1000
);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容