前言:
最近在读 JavaScript 设计模式这本书。好记性不如烂笔头,在这里做个笔记加深自己的理解。
我们首先要了解一下几个概念:
模式:一种可复用的解决方案,可用于解决软件设计中所遇到的常见问题。
模式的优点:
- 模式是已经验证的解决方案;
- 模式很容易被服用;
- 模式富有表达力;
模式的分类:
- 创建型设计模式:构造器(Constructor)、工厂(Factory)、抽象(Abstract)、原型(Prototype)、单例(Singleton)、生成器(Builder)。
- 结构型设计模式:装饰者(Decorator)、外观(Facade)、亨元(Flyweight)、适配器(Adapter)和代理(Proxy)。
- 行为设计模式:迭代器(Iterator)、中介者(Mediator)、观察者(Observer)和访问者(Visitor)。
Model(模块)模式
模块是任何一个强大的应用程序框架必不可少的一部分。模块模式在某种程度上是基于对象字面量,通过闭包的方式封装私有状态和组织。
模块模式提供一种包装混合私有/公有方法和变量的方式,防止其泄露至全局作用域,并与别的开发人员接口冲突。
简单的模板实现:
/**
* Created by Zang on 2017/3/12.
* 通过 Model 模式模拟实现购物车
*/
var basketModel = (function () {
// 私有
var _items = [];
return {
// 公有
addItem: function (item) {
_items.push(item);
},
getItemCount: function () {
console.log(_items.length);
},
getTotalPrices: function () {
if (_items.length === 0) {
console.log('购物车为空');
return;
}
var totalPrices = 0.0;
_items.forEach(function (item) {
totalPrices += item.number * item.prices;
});
console.log(totalPrices);
}
};
})();
basketModel.addItem({
name: 'JavaScript设计模式',
number: 1,
prices: 49.00
});
basketModel.addItem({
name: '精通AngularJS',
number: 1,
prices: 79.00
});
basketModel.getItemCount(); // 2
basketModel.getTotalPrices(); // 128
console.log(basketModel._items); // undefined
优点:
- 在 JavaScript立场,对于有面向对象背景的开发人员来说,相比真正的封装这样的代码更加简洁;
- 支持私有数据;
缺点:
- 无法为私有对象建立自动化单元测试;
- BUG修正补丁时会增加额外的复杂性,我们必须覆盖所有与BUG的私有对象有交互的公有对象;
- 开发人员无法轻易的扩展私有对象;
Revealing Model(揭示模块)模式
该模式是在模块模式的基础上进行改进。该模式在私有范围内简单定义所有的函数和变量,并返回一个匿名对象,它拥有指向私有函数的指针。
简单模板实现:(在Model示例基础上进行修改)
/**
* Created by Zang on 2017/3/12.
*/
var basketModel = (function () {
// 私有
var _items = [];
var _addItem = function (item) {
_items.push(item);
};
var _getItemCount = function () {
console.log(_items.length);
};
var _getTotalPrices = function () {
if (_items.length === 0) {
console.log('购物车为空');
return;
}
var totalPrices = 0.0;
_items.forEach(function (item) {
totalPrices += item.number * item.prices;
});
console.log(totalPrices);
};
return {
// 公有
addItem: _addItem,
getItemCount: _getItemCount,
getTotalPrices: _getTotalPrices
};
})();
basketModel.addItem({
name: 'JavaScript设计模式',
number: 1,
prices: 49.00
});
basketModel.addItem({
name: '精通AngularJS',
number: 1,
prices: 79.00
});
basketModel.getItemCount(); // 2
basketModel.getTotalPrices(); // 128
console.log(basketModel._items); // undefined
优点:除上述Model模式的优点外,其语法更加一致。很清晰的指出哪些是允许被公开访问的,可读性更高。
缺点:除上述Model模式的缺点外,其比Model模式更加脆弱。因为当一个私有对象指向公有函数,打补丁的时候不能将公有对象覆盖。
Singleton(单例)模式
单例模式限制了类的实例化次数只能是一次。当该实例不存在的时候,通过一个方法创建一个实例对象。如果存在则返回该对象的引用。
单例模式不同于我们使用的静态对象,我们可以推迟它的初始化。因为通常我们使用它时候需要一些信息,而这些信息在初始化阶段可能无法提供给我们。
在JavaScript中,单例充当的是共享资源命名空间,从全局命名空间中隔离出代码实现,从而为函数提供单一的访问接口。
简单模板实现:
/**
* Created by Zang on 2017/3/12.
*/
var singleton = (function () {
var instance = null;
var init = function () {
var _privateRandomNumber = Math.random();
return {
getPrivateRandomNumber: function () {
return _privateRandomNumber;
}
};
};
return {
getInstance: function () {
if (!instance) {
instance = init();
}
return instance;
}
};
})();
var badSingleton = (function () {
var instance = null;
var init = function () {
var _privateRandomNumber = Math.random();
return {
getPrivateRandomNumber: function () {
return _privateRandomNumber;
}
};
};
return {
getInstance: function () {
instance = init();
return instance;
}
};
})();
var singletonA = singleton.getInstance();
var singletonB = singleton.getInstance();
console.log(singletonA.getPrivateRandomNumber() === singletonB.getPrivateRandomNumber()); // true
var badSingletonA = badSingleton.getInstance();
var badSingletonB = badSingleton.getInstance();
console.log(badSingletonA.getPrivateRandomNumber() === badSingletonB.getPrivateRandomNumber()); // false
单例很有使用价值,当我们需要使用它的时候,则表示我们需要重新评估我们的设计。
单例的存在往往表明系统模块要么是紧密耦合,要么是逻辑过于分散。单例通常是用来加强紧密耦合。