设计模式

2019-04-02  本文已影响0人  磨人的磨磨虫

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
);
上一篇下一篇

猜你喜欢

热点阅读