《javascript设计模式与开发实践》读书笔记(6)

本次笔记记录本周学习的模版方法模式和享元模式。

模版方法模式

定义:模版方法模式由两部分组成,第一部分是抽象父类,第二部分是具体实现的子类。通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。简单来说,模版方法模式就是通过继承来把多个子类的公共部分进行封装。

一个简单例子

书中用了Coffee和Tea的例子来说明模版方法模式。
泡一杯咖啡需要四步:

  1. 把水煮沸
  2. 沸水冲咖啡
  3. 把咖啡倒进杯子
  4. 加糖和牛奶
    泡一杯茶与泡一杯咖啡的步骤相似:
  5. 把水煮沸
  6. 沸水浸泡茶叶
  7. 茶水倒进杯子
  8. 加柠檬
    泡茶和泡咖啡步骤相似,所以可以将公共部分分离出来,写到父类中。如下代码
var Beverage = function(){}
Beverage.prototype.boilWater = function(){
    console.log('把水煮沸')
}
Beverage.prototype.brew = function(){}
Beverage.prototype.pourInCup = function(){}
Beverage.prototype.addCondiments = function(){}
Beverage.prototype.init = function(){
    this.boilWater()
    this.brew()
    this.pourInCup()
    this.addCondiment()
}

定义完父类,可以在子类中对特定方法进行重写。比如Tea类:

var Tea = function(){}
Tea.prototype = new Beverage()
Tea.prototype.brew = function(){
    console.log('沸水浸泡茶叶')
}
Tea.prototype.pourInCup = function(){
    console.log('把茶倒进杯子')
}
Tea.prototype.addCondiments = function(){
    console.log('加柠檬')
}

var tea = new Tea()
tea.init()

这个例子中,Beverage.prototype.init就是模版方法,其指导了子类以何种顺序执行哪些方法。

抽象类

从上面的例子可以看出,模版方法模式的父类是一个抽象类,其不应该被实例化。在js语言中,并没有对抽象类的支持,编译器不会检查子类是否重写了父类的“抽象方法”。所以在js中实现抽象类,需要在抽象类的抽象方法中抛出异常,以便在程序运行中可以知道哪里出错了。也可以用鸭子类型来模拟接口检查,在创建对象时来发现问题,但这种方法实现起来较复杂(具体实现后续研究一下)。

钩子方法

钩子方法是指,在父类中放置钩子,根据钩子方法的返回值,决定是否执行某些方法,钩子方法的返回由子类决定。这样可以给方法的执行增加灵活性。实现起来也很简单,用if语句即可。

好莱坞原则

好莱坞原则是指底层组件把自己挂钩到高层组件,高层组件决定什么时候,以何种方式来调用底层组件。模版方法模式就是好莱坞原则的一个使用场景。根据好莱坞原则,我们实际并不需要一个“正宗”的通过继承实现的模版方法模式,在js语言中,我们完成可以不通过继承来实现。代码如下:

var Beverage = function(param){
    var boilWater = function(){
        console.log('把水煮沸')
    }

    var brew = param.brew || function(){
        throw new Error('必须传递brew方法')
    }

    var pourInCup = param.pourInCup || function(){
        throw new Error('必须传递pourInCup方法')
    }

    var addCondiments = param.addCondiments || function(){
        throw new Error('必须传递addcondiments方法')
    }

    var F = function(){}

    F.prototype.init = function(){
        boildWater()
        brew()
        pourInCup()
        addCondiments()
    }

    return F
}

var Coffee = Beverage({
    brew: function(){
        console.log('用沸水冲泡咖啡')
    },
    pourInCup: function(){
        console.log('把咖啡倒进杯子')
    },
    addCondiments: function(){
        console.log('加糖和牛奶')
    }
})

var coffee = new Coffee()
coffee.init()

总结

模版方法模式就是通过抽象父类来定义子类的方法和执行顺序,子类来完成具体方法的实现。在js中往往不需要严格通过继承来实现这一模式。

享元模式

定义:享元模式是一种用于性能优化的模式,享元模式的核心是运用共享技术来有效支持大量细粒度的对象。享元模式要求将对象划分为内部状态和外部状态。

  • 内部状态存储于对象内部
  • 内部状态可以被一些对象共享
  • 内部状态独立于具体场景,通常不会改变
  • 外部状态取决于具体场景,并根据场景而变化,外部状态不能被共享
    共享模式的目标就是尽量减少共享对象的数量。将所有内部状态放置在一个共享对象中,外部状态在必要的时候被传入共享对象来组装成一个完整的对象。享元模式是一种用时间换空间的优化模式。

文件上传例子

对于多文件上传,如果同时上传2000个文件,不考虑享元模式,那么你将new 2000个文件对象,这是很大的内存开销。下面用享元模式来进行编写代码。
首先明确,上传类型为内部状态,文件名和文件大小为外部状态

  1. 构造函数
    var Upload = function(uploadType){
     this.uploadType = uploadType
    }
  2. 工厂进行对象实例化

    var UploadFactory = (function(uploadType){
     var createdFlyWeightObjs = {}
    
     return {
         create: function(uploadType){
             if(createdFlyWeightObjs[uploadType]){
                 return createdFlyWeightObjs[uploadType]
             }
             return createdFlyWeightObjs[uploadType] = new Upload(uploadType)
         }
     }
    })()
  3. 管理器封装外部状态

    var uploadManager = (function(){
     var uploadDatabase = {}
    
     return {
         add: function(id, uploadType, fileName, fileSize){
             var flyWeightObj = UploadFactory.create(uploadType)
             uploadDatabase[id] = {
                 fileName: fileName,
                 fileSize: fileSize
             }
             return flyWeightObj
         },
         setExternalState: function(id, flyWeight){
             var uploadData = uploadDatabase[id]
             for(var i in uploadData){
                 flyWeightObj[i] = uploadData[i]
             }
         }
     }
    })()

对象池
对象池很好理解,在对象池中定义一定数量的对象,当需要的时候,直接从对象池中获取,而不需要去创建新对象,只有当对象池中的对象数量不满足需求时,就新创建一个对象,并放到对象池中。

总结

享元模式是为解决性能问题而生的模式,通过区分内部状态和外部状态来减少对象的产生。

#笔记##设计##读书笔记#
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务