JAVAScript 创建对象 的13种 设计模式(上)
要掌握设计模式,首先接触的是 高阶函数(higher-order function)[1]
高阶函数的应用:
-
回调函数:
- 事件、ajax、所有涉及到异步通信的几乎都是回调函数()node.js
-
dom事件
一、单例模式
理论: 整个程序只包含一个实例;保证实例公有一个类,
并提供一个访问它的全局访问点(实例化的都指向同一区域)。
优点:节约内存;在 JavaScript 里,单例作为一个命名空间提供者,
从全局命名空间里提供一个唯一的访问点来访问该对象,避免全局污染。
缺点:字面量实现方式即使不用也占用内存,延迟方式,
当调用 getInstance的时候才分配内存,如果单例对象非常复杂,
则延迟模式(惰性加载)更好。
1 字面量形式
通过 对象字面量 的形式(json格式)
var obj = {
name: 'wang',
showName: function() {
console.log(this.name);
}
};
var o1 = obj;
var o2 = obj;
<!-- o1 === o2 -->
// 复杂类型是将obj变量存于栈中,通过指针指向堆中的存储空间
2.通过 构造函数 的方式(改变指针指向,确保只开辟一个空间)
function Obj(){
<!-- 为保证只有一个实例,定义一个变量,判断是否有该实例 -->
if(Obj.a !== undefined) {
//第二次实例化的时候通过保存的变量改变指针
return Obj.a;
}
this.sum = 0;
this.getPrice = function(price){
this.sum += price;
return this.sum;
};
// 保存变量(关键)
Obj.a = this;
}
var o1 = new Obj();
var o2 = new Obj();
o1 === o2 // 值 与 类型都相同(后端语言包含地址)
3.函数 闭包 链式访问形式(命名空间)
var Product = (function() {
var unique;
var sum = 0;
// 判断函数
function getInstance() {
if(!unique) {
unique = construct();
};
return unique;
};
// 保存单利对象的函数
function construct() {
return {
getPrice: function() {},
addCart: function() {}
// 可以保存更多的方法及属性
};
};
})();
// 链式调用方法
Product.getInstance().getPrice();
二、工厂模式
理论:通过使用工厂方法而不是new关键字及具体类,把所有实例化的代码都集中在一个位置。
优点:有助于创建模块化的代码,消除对象之间的耦合。
- 大型项目扩展影响小
- 有助于提高项目的扩展性、灵活性
- 封装性(封装创建过程)
缺点:
- 新增流水线,将不利于改造
1.普通方式
函数内部实例,并返回对象
function Obj(name) {
// 创建对象,并对对象拓展属性及方法
var o = new Object();
o.name = name;
o.show = function() {
alert(this.name);
}
// 将对象返回
return o;
};
<!-- 创建需要的obj -->
var doSome = Obj('wang');
<!-- obj1 == obj2 // false -->
2.零模式
(1)工厂对象
var Factory = function() {}; //构建工厂
Factory.prototype = { //工厂返回实例
create:function(type){
var product;
switch(type) {
case:'one':
product = new OnePro();
break;
case:'two':
product = new TwoPro();
break;
}
return product;
}
};
// 通过工厂返回相应的实例,而不是this的链式访问
// 定义 products 分类
var OnePro = function() {}; // 分类一
OnePro.prototype = {
name: 'one',
getName:function(){
return this.name;
}
}
var TwoPro = function() {}; // 分类二
TwoPro.prototype = {
name: 'two',
getName:function(){
return this.name;
}
}
(2)工厂函数
function factory(type) {
var product;
switch(type) {
case:'one':
product = new OnePro();
break;
case:'two':
product = new TwoPro();
break;
};
return product;
};
// 直接调用函数即可创建分类对象
3.普通函数采用工厂模式实现new
4.团队应用工厂模式
(1)团队一、算法:
var Price = {}; // 创建命名空间
Price.vip = function() { // 分类一
this.dis = 0.3;
this.getPrice = function(price) {
return price * this.dis;
}
};
Price.old = function() { // 分类二
this.dis = 0.5;
this.getPrice = function(price) {
return price * this.dis;
}
};
Price.normal = function() { // 分类三
this.dis = 0.7;
this.getPrice = function(price) {
return price * this.dis;
}
};
// 对新增分类有好处 直接添加即可
(2)团队二、
<!-- 生产不同的实例 不关心如何定义 -->
Price.factory = function(type){
return new Price[type]
}
(3)团队三、
<!-- 使用对象的接口 不关心内部构造 -->
var nomalPrice = Price.factory('normal');
nomalPrice.getPrice(1000);
三、策略模式[2]
步骤:
- 定义算法对象
- 算法对象是为了解决频繁的扩展方法问题
- 定义上下文
- 上下文是为了框架的使用简洁化,不用关心算法细节
- 使用
优点:解耦合 模块化
应用:
- 保护核心系统
- 屏蔽复杂对象
- 延迟加载
- 通过代理模式实现延迟加载
- jqurey插件实现延迟加载
1.策略模式
<!-- 定义不同的计算函数 -->
var vip = function(price) {
return price * 0.3; //执行算法代码
};
var old = function(price) {
return price * 0.5; //执行算法代码
};
var nomal = function(price) {
return price * 0.7; //执行算法代码
};
// 定义调用函数部分(定义上下文)
var calculate = function(fn,price){
return fn(price);
};
// 使用部分
var price = calculate(vip,1000);
2.类反射方式
<!-- 定义对象 存放各 类 的计算方法 -->
var class = {
"vip":function(price) {
return price * 0.3; //执行算法代码
},
"old":function(price) {
return price * 0.5; //执行算法代码
},
"nomal":function(price) {
return price * 0.7; //执行算法代码
}
};
// 全局污染减少
var calculate = function(leval,price){
// 反射机制
return class[leval](price);
};
// 使用部分
var price = calculate("vip",1000);
四、观察者模式(Observer):双向绑定的本质
理论: 又称作:表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式、从属者(Dependents)模式、
- 注册:
- dom事件入队列(存入数组)
- 监听:
- 执行事件
- 响应:
- 执行回调函数
1.观察者模式其实就是实现异步编程,javascript本身就是支持异步编程的语言。这是它的强大之处。
2.观察者模式是利用函数回调来实现异步编程,当事件触发时,所有订阅者都会受到消息,并调用对应的处理函数,而不用实时监测,这显然在某些情况下,极大的提高了cpu的利用率。
3.自定义事件就是异步编程的实际运用,让你可以将操作代码在你想要执行的时候去执行(触发事件),而不是传统的从上到下执行,增加了代码灵活性。并且,减少 了代码冗余,同样的操作,只需要触发同样的事件就行了,不需要再写一遍。
优点:
- 支持简单的广播通信,自动通知所有已经订阅过的对象
- 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用(高内聚,低耦合)
缺点:
扩充----事件轮询(Event Loop)[^3]
[^3]:指的是计算机系统的一种运行机制。(JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。);主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件轮询)
一般情况下,一个进程一次只能执行一个任务。如果有很多任务需要执行,不外乎三种解决方法。 (1)排队:因为一个进程一次只能执行一个任务,只好等前面的任务执行完了,再执行后面的任务。 (2)新建进程:使用fork命令,为每个任务新建一个进程。 (3)新建线程:因为进程太耗费资源,所以如今的程序往往允许一个进程包含多个线程,由线程去完成任务。
五、代理模式
理论:代理模式就是用一个类来代替另一个类来执行方法功能
优点:
缺点:
六、装饰者模式
理论:
优点:
缺点: