什么是设计模式
有人说设计模式是能被反复使用、多数人知道的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码,让代码更容易被他人理解、保证代码的可靠性。
个人认为,设计模式其实就是前端工程化编程的一种思想,将代码 能够理解成更贴近生活的一种经验。年纪大了,就知道做什么,怎么做,怎么能做的更好,编程也一样,时间长了,就更明白什么需求应该采用什么方式编写,这种一贯的编写方式于是被总结为设计模式,我们现在用的这些模式,其实就是前辈的经验总结,能避免我们绕弯路,更好的编程。
设计模式有很多
- 单体/单例模式
- 观察者模式
- 工厂模式
- 策略模式
- 模板模式
- 代理模式
- 外观模式
….
我们常用的也就是 单体模式、工厂模式、单例模式、观察者模式、策略模式,其他的可能没用到,或者无形中用到了但没注意是什么模式,不管是什么模式,能够被重用的,可维护的代码,都是好的程序
一、单体/单例模式
单例模式在js中我们随处都见,一个类只能保证有一个实例,例如对象字面量的方式创建一个单例,他可以定义很多的属性和方法,这个类也只有一个实例对象。优点,能够单独划分一个命名空间,避免和别人的内部变量发生冲突,所以单例可以分为简单的单例和闭包单例
简单单例
//先判断实例是否存在,存在则返回,不存在则创建,这样可以保证一个类只有一个实例对象 var test_simple = test_simple || { name: 'alice', age: 15, gender: '2', sayName: function(){ console.log('my name is ' + this.name) }, sayAge: function(){ console.log('i am '+ this.age + ' years old') } }
闭包单例
闭包的作用是保护一些私有属性,不让外界访问,只有return将属性暴露才能被外界访问 var test_Closure = test_Closure || { introduce = (function(){ var _name = 'bob', //定义私有属性 var _age = 18, var _gender = '1', var _sayName = function(){ console.log('my name is ' + _name) }, var _sayAge = function(){ console.log('i am '+ _age + ' years old') } //将属性暴露 让别人看看 return { name: _name, age : _age, gender : _gender, sayName : function(){ return _sayName(); }, sayAge : function(){ return _sayAge(); } } })() } //调用 test_Closure.sayName(); =>'my name is bob' test_Closure.sayAge(); =>'i am 18 years old'
二、观察者模式
观察者模式也是我们常用的设计模式,也叫”发布-订阅”模式,当一个对象的状态发生改变,依赖于他的对象都得到通知并自动刷新
例如vue的双向数据绑定的原理:
当我们在表单输入框中输入(发布)message的时候,依赖(订阅)他的地方都会被更改
一句话描述:一个页面在多处订阅使用了同一个数据,用Object.defineProperty监听其改变,并由发布者通知 订阅者 去更新它所持有的数据
具体实现请参照 https://segmentfault.com/a/11…
实现一个分蛋糕案例
1、onserver.js
var Observer = {}; //定义一个对象 包括三个方法 订阅 发布 退订
(function (_observer) {
var subListObj = {}, // 回调函数存放的数组
subId = -1; //订阅者id
// 发布 传入两个参数 (订阅主题,具体内容)
_observer.publish = function (subTip, args) {
if (!subListObj[subTip]) {
return false; //判断是否有订阅者
}
setTimeout(function () {
var subscribers = subListObj[subTip], //定义一个数组用来存储所有订阅者
len = subscribers ? subscribers.length : 0;
while (len--) { //只要发布者一发布就会遍历所有订阅者,分发信息
subscribers[len].func(subTip, args);
}
}, 0);
return true;
};
//订阅
_observer.subscribe = function (subTip, func) {
if (!subListObj[subTip]) {
subListObj[subTip] = [];
}
var token = (++subId).toString(); //订阅者唯一标识
subListObj[subTip].push({ //接收信息
token: token,
func: func //func不仅是一个动作 数据更新的回调
});
// console.log(token) // => {example1:[0,func]}{example1:[1,func]}
return token;
};
//退订
_observer.unsubscribe = function (token) { //退订 传入订阅者的id进行过滤 如果退订就splice删除
for (var m in subListObj) {
if (subListObj[m]) {
for (var i = 0, j = subListObj[m].length; i < j; i++) {
if (subListObj[m][i].token === token) {
subListObj[m].splice(i, 1);
console.log('我' + token + '不吃了')
return token;
}
}
}
}
return false;
};
} (Observer));
2、过来吃蛋糕啦 index.html
<script src="./js/observer.js"></script>
<script>
//来,订阅一个
Observer.subscribe('subCake', function (subTip, data) {
console.log(subTip + ": " + data);
});
//来,再订阅一个
Observer.subscribe('subCake', function (subTip, data) {
console.log(subTip + "我来啦.." + data);
});
//0不吃了
Observer.unsubscribe('0')
//发布通知
Observer.publish('subCake', '快来分蛋糕...');
</script>
如果0没有退订:
subCake我也收到了..快来分蛋糕...
subCake: 快来分蛋糕...
0退订了:
我0不吃了
subCake我也收到了..快来分蛋糕...
三、工厂模式
工厂模式:提供创建对象的接口,封装一些公用的方法,如果实现具体的业务逻辑,可以放在子类重写父类的方法
优点:弱化对象间的耦合,防止代码重复
缺点:简单业务可以用,复杂的业务会导致代码维护性差,不易阅读
//声明一个蛋糕店 负责做蛋糕 和 卖蛋糕
var CakeShop = function(){}
CakeShop.prototype = {
sellCake: function(){
},
makeCake: function(type){
console.log('aaa')
}
}
//定义一个继承的方法
var Extend = function(desc, src){
for(var property in src){
desc[property] = src[property]
}
return desc;
}
Object.extend = function(obj){
return Extend.apply(this,[this.obj])
}
//声明一个水果蛋糕,从蛋糕店
var FruitCake = function(){}
Object.extend(FruitCake, CakeShop);
console.log(FruitCake.prototype)
FruitCake.prototype.makeCake = function(type){
var cake;
switch (type){
case 'apple':
cake = new AppleCake();break;
case 'pear':
cake = new Pear();break;
default:
cake = new Orange();break;
}
return cake;
}
var buyCake = new FruitCake();
var myCake = buyCake.sellCake('apple')
console.log(myCake)
策略模式
策略模式是一种很好的编程思想,可以用来解决多个if条件语句,能够代码复用,逻辑清晰,也容易扩展。
来来来,上代码
//以前你是这样的
var buyCar = function(brand){
if(brand == '奥迪') {
return '大于80万'
}
if(brand == 'QQ') {
return '小于10万'
}
if(brand == 'ofo') {
return '小于1000元'
}
}
console.log(buyCar('ofo')) // => 小于1000元
//那么现在你应该这样
var buyCars = {
'奥迪': function(){
return '大于80万'
},
'QQ': function(){
return '小于10万'
},
'ofo': function(){
return '小于1000元'
}
}
var result = function(brand){
return buyCars[brand]();
}
console.log(result('ofo')) // => 小于1000元
// 系不系很简单
设计模式还有很多,有时间还会继续学习…