设计模式
听起来像很是高端的样子,其实呢,确实很提莫难啊啊啊啊。言归正传,所谓的设计模式也就是一些比较优秀的编程思想。有了这些思想加于利用到实际开发中,可以减少工作量(便于维护)。废话不多说直接进入主题。
工厂模式
工厂模式,顾名思义,就是为了创造对象。也就是一些公共方法???
工厂模式最重要的优点是:可以在父类实现一些相同的方法,而具体要实现的业务逻辑可以放在子类中,通过子类重写父类的方法,去实现自己的业务逻辑,减少冗余代码。
简单工厂模式
1 | function CarFactory (brand, price) { |
函数CarFactory接受两个参数brand, price,最终返回一个对象。如果多次调用这个函数,每次将返回一个新的对象,这就跟工厂的生产线一样。
复杂工厂模式
1 | function ComplexCarFactory(brand, price) { |
ComplexCarFactory为父类,CarChild为子类,CarChild继承自ComplexCarFactory。
ComplexCarFactory不在进行对象实例化,只对创建过程中的一般性问题进行处理,ComplexCarFactory就像是Java中的抽象类,必须被子类重写,否则调用ComplexCarFactory的getSpeed方法时就会抛出异常。
CarChild继承自ComplexCarFactory,同时重写了父类的方法,CarChild类实例后的对象之间是相互独立的,具体的业务逻辑会放在子类中进行编写。
单例模式
单例模式思想在于保证一个特定类仅有一个实例,意味着当你第二次使用同一个类创建信对象时,应得到和第一次创建对象完全相同。
单例模式在我们平时的应用中用的比较多的,相当于把我们的代码封装在一个起来,只是暴露一个入口,从而避免全部变量的污染。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var Singleton = function(name){
this.name = name;
};
Singleton.prototype.getName = function(){
return this.name;
}
// 获取实例对象
var getInstance = (function() {
var instance = null;
return function(name) {
if(!instance) {
instance = new Singleton(name);
}
return instance;
}
})();
// 测试单例模式的实例
var a = getInstance("aa");
var b = getInstance("bb");
console.log(b.getName()); // "aa"
console.log(a === b); // true
实现一个单例模式,无非就是使用一个变量来标识该类是否被实例化,如果未被实例化的话,那么我们可以实例化一次,否则的话,直接返回已经被实例化的对象。
模块模式
模块模式是为单例模式添加私有变量和私有方法,并减少全局变量的使用;
使用场景,创建一个对象时,需要进行内部初始化,同时对内部属性跟方法有访问权限限制,就需要使用模块模式了。
如下就是一个模块模式的代码结构:1
2
3
4
5
6
7
8
9
10
11
12
13
14var singleMode = (function(){
// 创建私有变量
var privateNum = 112;
// 创建私有方法
function privateFunc(){},
// 创建公有方法
function publicMethod1(){},
function publicMethod2(){},
// 返回一个对象包含公有方法和属性
return {
publicMethod1: publicMethod1,
publicMethod2: publicMethod2
};
})();
模块模式使用了一个返回对象的匿名函数。在这个匿名函数内部,先定义了私有变量和函数,供内部函数使用,然后将一个对象字面量作为函数的值返回,返回的对象字面量中只包含可以公开的属性和方法。这样的话,可以提供外部使用该方法;由于该返回对象中的公有方法是在匿名函数内部定义的,因此它可以访问内部的私有变量和函数。
代理模式
代理模式的优点在于:代理对象可以代替本体对象被实例化,此时本体对象未真正实例化,等到合适时机再实例化。代理模式可以延迟创建开销很大的本体对象,他会把本体的实例化推迟到有方法被调用时。
图片加载
使用图片是非常常见的场景,如果直接给img标签设置src属性,如果图片过大,或网速比较慢,图片在加载过程中会有一段时间的空白,用户体验不好。
1 | var myImage = (function(){ |
myImage 函数只负责做一件事,创建img元素加入到页面中,其中的加载loading图片交给代理函数ProxyImage 去做,当图片加载成功后,代理函数ProxyImage 会通知及执行myImage 函数的方法,同时当以后不需要代理对象的话,我们直接可以调用本体对象的方法即可。
缓存代理
对第一次运行的结果进行缓存,当再一次运行相同运算的时候,直接从缓存里面取,避免重复运算,如果运算非常复杂的话,对性能很耗费,那么使用缓存对象可以提高性能。以下是一个简单的例子1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33var mult = function(){
var a = 1;
for(var i = 0,ilen = arguments.length; i < ilen; i+=1) {
a = a*arguments[i];
}
return a;
};
// 计算加法
var plus = function(){
var a = 0;
for(var i = 0,ilen = arguments.length; i < ilen; i+=1) {
a += arguments[i];
}
return a;
}
// 代理函数
var proxyFunc = function(fn) {
var cache = {}; // 缓存对象
return function(){
var args = Array.prototype.join.call(arguments,',');
if(args in cache) {
return cache[args]; // 使用缓存代理
}
return cache[args] = fn.apply(this,arguments);
}
};
var proxyMult = proxyFunc(mult);
console.log(proxyMult(1,2,3,4)); // 24
console.log(proxyMult(1,2,3,4)); // 缓存取 24
var proxyPlus = proxyFunc(plus);
console.log(proxyPlus(1,2,3,4)); // 10
console.log(proxyPlus(1,2,3,4)); // 缓存取 10
职责链模式
策略模式
一、策略模式可以有效避免很多if条件语句 二、策略模式符合开放-封闭原则,使代码更容易理解和扩展 三、策略模式中的代码可以复用.
表单检验是非常常见的功能。因为涉及到大量的验证规则,使用策略模式会非常便利。
1 | // 策略对象 |
发布-订阅模式
发布—订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
eg:假设小🐶看上了一双鞋子,但该鞋子已经断货了,卖家承诺她到货通知。与此同时,小🐷、小🐒也关注了这双鞋子。
在这个场景中,卖家就是发布者,小🐶,🐷,🐒等人都属于订阅者。当鞋子到货时,会依次通知到每个人。
实现:
1.首先要想好谁是发布者(比如上面的卖家)。
2.然后给发布者添加一个缓存列表,用于存放回调函数来通知订阅者(比如上面的买家收藏了卖家的店铺,卖家通过收藏了该店铺的一个列表名单)。
3.最后就是发布消息,发布者遍历这个缓存列表,依次触发里面存放的订阅者回调函数。
1 | var Event = (function(){ |