js设计模式4-享元模式

享元模式,结构型设计模式之一,运用共享内部状态/外部状态来减少创建对象的数量,从而减少内存占用、提高性能。

享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生产大量细粒度的类实例来表示数据,把那些参数移动到类实例的外面,在方法调用的时候将他们传递进来,就可以通过共享大幅度第减少单个实例的数目。

使用场景:

第一种是应用在数据层上,主要是应用在内存里大量相似的对象上;

第二种是应用在DOM层上,享元可以用在中央事件管理器上用来避免给父容器里的每个子元素都附加事件句柄。

 实战一:

我们常见的面向对象的写法,就是像下面这样,一股脑的把对象的所有属性和方法,全部列出出来,然后再不断的new,要多少实例就new多少次,这种粗暴的方式,会占据大量的内存,应用很卡。

var Book = function( id, title, author, genre, pageCount,publisherID, ISBN, checkoutDate, checkoutMember, dueReturnDate,availability ){
  this.id = id;
  this.title = title;
  this.author = author;
  this.genre = genre;
  this.pageCount = pageCount;
  this.publisherID = publisherID;
  this.ISBN = ISBN;
  this.checkoutDate = checkoutDate;
  this.checkoutMember = checkoutMember;
  this.dueReturnDate = dueReturnDate;
  this.availability = availability;
};
Book.prototype = {
  getTitle:function(){
      return this.title;
  },
  getAuthor: function(){
      return this.author;
  },
  getISBN: function(){
      return this.ISBN;
  },
/*其它get方法在这里就不显示了*/

// 更新借出状态
  updateCheckoutStatus: function(bookID, newStatus, checkoutDate,checkoutMember, 
     newReturnDate){
      this.id  = bookID;
      this.availability = newStatus;
      this.checkoutDate = checkoutDate;
      this.checkoutMember = checkoutMember;
      this.dueReturnDate = newReturnDate;
  },
//续借
  extendCheckoutPeriod: function(bookID, newReturnDate){
   this.id =  bookID;
   this.dueReturnDate = newReturnDate;
  },
//是否到期
  isPastDue: function(bookID){
   var currentDate = new Date();
   return currentDate.getTime() > Date.parse(this.dueReturnDate);
  }
};

我们都知道,构造函数里面的属性是每个实例各自所有的,但是一个对象的属性,一本书为例,它的页码,书名,作者,版本,ISBN等都是固有的,不管谁买去用,书就是这本书,我们可以把这些属性作为内部属性/数据, 像谁买了,买去干什么了,什么时候卖掉的的,这是可以作为外部数据,是变动的。

所以我们利用享元模式优化如下:

//书就是那本书

 

var Book = function(title, author, genre, pageCount, publisherID, ISBN){
  this.title = title;
  this.author = author;
  this.genre = genre;
  this.pageCount = pageCount;
  this.publisherID = publisherID;
  this.ISBN = ISBN;
};

//会有很多书的实例不断穿件,所以我们需要借助工厂方法和单例

然后创一个管理书的状态的方法类

/*BookRecordManager 借书管理类 单例*/
var BookRecordManager = (function(){
  var bookRecordDatabase = {};  //对象池
  return{
      /*添加借书记录*/
    addBookRecord: function(id, title, author, genre,pageCount,publisherID,ISBN, checkoutDate, checkoutMember, dueReturnDate, availability){
        var book = BookFactory.createBook(title, author, genre,pageCount,publisherID,ISBN); //生成一本书,
            bookRecordDatabase[id] ={
            checkoutMember: checkoutMember,
            checkoutDate: checkoutDate,
            dueReturnDate: dueReturnDate,
            availability: availability,
            book: book
        };
        return book;
    },
    getBook:function(id){
      return bookRecordDatabase[id].book;
    },
    getTitle:function(id){
      return bookRecordDatabase[id].book.title
    },
    getAuthor:function(id){
      return bookRecordDatabase[id].book.author
    },
    getDueReturnDate:function(id){
      return bookRecordDatabase[id].dueReturnDate
    },
   updateCheckoutStatus: function(bookID, newStatus, checkoutDate, checkoutMember,newReturnDate){
       var record = bookRecordDatabase[bookID];
       record.availability = newStatus;
       record.checkoutDate = checkoutDate;
       record.checkoutMember = checkoutMember;
       record.dueReturnDate = newReturnDate;
       return record;
  },
  extendCheckoutPeriod: function(bookID, newReturnDate){
      bookRecordDatabase[bookID].dueReturnDate = newReturnDate;
  },
  isPastDue: function(bookID){
      var currentDate = new Date();
      return currentDate.getTime() > Date.parse(bookRecordDatabase[bookID].dueReturnDate);
  }
};
})();

//最后我们来使用

var a = BookRecordManager.addBookRecord(1,"寻秦记", "古龙", 2,30000,0001,"ISBN-1000","checkoutDate", "checkoutMember", "dueReturnDate", "availability")
BookRecordManager.addBookRecord(2,"神雕侠侣", "金庸", 1,20000,0001,"ISBN-2010","checkoutDate000", "checkoutMember000", "dueReturnDate000", "availability000")
var b = BookRecordManager.updateCheckoutStatus(1,"checkoutDate1111", "checkoutMember1111", "dueReturnDate1111", "availability1111")
var c = BookRecordManager.extendCheckoutPeriod(1,"dueReturnDate2222")

console.log(BookRecordManager.getBook(1))
console.log(BookRecordManager.getTitle(1))
console.log(BookRecordManager.getAuthor(1))
console.log(BookRecordManager.getDueReturnDate(1))


console.log(BookRecordManager.getBook(2))
console.log(BookRecordManager.getTitle(2))
console.log(BookRecordManager.getAuthor(2))

另外一个案例

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="http://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(() => {
  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
);

本系列所有的案例均来自网络

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风清云淡_A

觉得有帮助的话可以给点鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值