深入理解JavaScript系列(37):设计模式之享元模式详解
介绍
享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。
享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生产大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数以外,开销基本相同的话,就可以大幅度较少需要实例化的类的数量。如果能把那些参数移动到类实例的外面,在方法调用的时候将他们传递进来,就可以通过共享大幅度第减少单个实例的数目。
那么如果在JavaScript中应用享元模式呢?有两种方式,第一种是应用在数据层上,主要是应用在内存里大量相似的对象上;第二种是应用在DOM层上,享元可以用在中央事件管理器上用来避免给父容器里的每个子元素都附加事件句柄。
享元与数据层
Flyweight中有两个重要概念--内部状态intrinsic和外部状态extrinsic之分,内部状态就是在对象里通过内部方法管理,而外部信息可以在通过外部删除或者保存。
说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,很显然,在这里需要产生不同的新对象,所以Flyweight模式中常出现Factory模式,Flyweight的内部状态是用来共享的,Flyweightfactory负责维护一个Flyweightpool(模式池)来存放内部状态的对象。
使用享元模式
让我们来演示一下如果通过一个类库让系统来管理所有的书籍,每个书籍的元数据暂定为如下内容:
ID Title Author Genre Pagecount PublisherID ISBN
我们还需要定义每本书被借出去的时间和借书人,以及退书日期和是否可用状态:
checkoutDate checkoutMember dueReturnDate availability
因为book对象设置成如下代码,注意该代码还未被优化:
varBook=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(){ returnthis.title; }, getAuthor:function(){ returnthis.author; }, getISBN:function(){ returnthis.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){ varcurrentDate=newDate(); returncurrentDate.getTime()>Date.parse(this.dueReturnDate); } };