文章目录
一、设计模式
1.1 什么是设计模式
一套经过反复使用、多人知晓的、经过分类的、代码设计经验的总结
1.2 为什么使用设计模式:
为了代码的可重用性、让代码更容易被他人理解、保证代码的可靠性。设计模式使代码的编写真正的工程化;设计模式是软件工程的基石脉络,如同大厦的结构
1.3 有哪些设计模式(来自W3Cschool,23种):
构造器模式,模块化模式,暴露模块模式,单例模式,中介者模式,原型模式,命令模式,外观模式,工厂模式,Mixin模式,装饰模式,亨元(Flyweight)模式,MVC模式,MVP模式,MVVM模式,组合模式,适配器模式,外观模式,观察者模式,迭代器模式,惰性初始模式,代理模式,建造者模式
二、单例模式
单个实例,只有一个对象
//多次创建,返回同一个对象
function fn(){
if(!fn.obj) { //给函数添加一个属性。 因为函数是全局的,所以该属性一旦添加一直存在;
fn.obj = {
name : “liyang"
};
}
return fn.obj;
}
var obj1 = new fn();
var obj2 = new fn();
console.log(obj1 == obj2);
//例如我们创建一个信息提示框,每一次执行toast方法,如果都创建一个新的元素,这样做太浪费了。
//因此,我们采取单例模式,确保无论调用多少次toast方法,都只创建一个DOM元素。
//我们只控制它的显示和隐藏,而不是每次创建每次销毁。
function Toast(){
var div = document.createElement("div");
div.className = "box";
document.body.appendChild(div);
setTimeout(function(){
div.remove();
},1000)
}
obtn.onclick = function(){
var a = new Toast();
var b = new Toast();
console.log(a == b)
}
function Toast(){
if(!Toast.div){
Toast.div = document.createElement("div");
Toast.div.className = "box";
document.body.appendChild(Toast.div);
clearTimeout(Toast.div.timer);
Toast.div.timer = setTimeout(function(){
Toast.div.style.display = "none";
},1000)
}else{
Toast.div.style.display = "block";
clearTimeout(Toast.div.timer);
Toast.div.timer = setTimeout(function(){
Toast.div.style.display = "none";
},1000)
}
return Toast;
}
obtn.onclick = function(){
var a = new Toast();
var b = new Toast();
console.log(a == b);
}
三、组合模式
把多个对象组成树状结构来表示局部与整体,使得用户可以同时操作单个对象和对象的组合。
- 可以以相同的方法处理对象的集合与其中的特定子对象。组合对象与组成该对象的对象可实现同一批的操作,对组合对象执行的操作会向下传递到所有的组成对象,使得所有组成对象都会执行同样的操作。
- 可以将对象组织成树状结构,并且使整棵树可被遍历,所有组合对象都实现一个用来获取其子对象的方法,借助该方法可以隐藏实现的细节,组织子对象,使子对象内部的实现不形成依赖
对于创建动态用户界面来说,组合模式可以算是为其量身定做的,因为HTML结构正好符合组合模式适用场景的结构。
- 存在一批组织成某种层次体系的对象
- 希望对这批对象或者其中某一部分对象实施一个操作
组合模式擅长对大批量对象进行操作,转为组织这类对象把操作从一个层次向下一个层次传递设计,借此可以弱化对象间的耦合关系并且可以互换使用一些类或者实例,使代码模块化程度更高,维护更容易。
function ImagesStore( id ){
this.children = [];
this.element = document.createElement("div");
this.element.id = id;
this.element.className = "imgs-store";
document.body.appendChild(this.element)
}
ImagesStore.prototype = {
constructor : ImagesStore,
add:function( child ){
this.children.push( child );
this.element.appendChild( child.getElement() );
},
remove:function( child ){
for( var node, i=0; node = this.getChild(i); i++ ){
if( node === child ){
this.children.splice( i, 1 );
break;
}
}
this.element.removeChild( child.getElement() );
},
getChild:function( i ){
return this.children[i];
},
show:function(){
this.element.style.display = '';
for( var node, i=0; node = this.getChild(i); i++ ){
node.show();
}
},
hide:function(){
for( var node, i=0; node = this.getChild(i); i++ ){
node.hide();
}
this.element.style.display = 'none';
},
getElement:function(){
return this.element;
}
}
//上面的组合对象中我们可以看出,原型上的hide和show方法不单单是对于当前element进行处理,还延伸到其包含的每一个叶对象上执行。这边就体现了组合模式的运行机制,一条命令在多个对象上激发复杂的或者递归的行为。
function ImageItem( src ){
this.element = document.createElement("img");
this.element.src = src;
this.element.className = "img-item";
}
ImageItem.prototype = {
constructor:ImageItem,
add:function( child ){
console.log("this is image object, no add function");
},
remove:function( child ){
console.log("this is image object, no remove function");
},
getChild:function( i ){
console.log("this is image object, no getChild function");
},
show:function(){
this.element.style.display = '';
},
hide:function(){
this.element.style.display = 'none';
},
getElement:function(){
return this.element;
}
}
使用组合模式组织起来的对象具有出色的层次结构,每当对顶层组合对象执行一个操作的时候,实际上是在对整个结构进行深度优先的节点搜索。但是这些优点都是用操作的代价换取的,比如每次顶级执行一次show方法,实际的操作就是整个树形结构的节点都会被遍历一次。但是组合对象的每个对象之间的耦合非常松散,可以简单的操作处理复杂的结果。
简单的说,组合模式是讲一批子对象组织为树形结构,一条顶层的命令会在操作树中所有的对象。提高了代码的模块化程度,对于动态的HTML界面具有很强的适用性
四、观察者模式
观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
使用观察者模式的好处:
- 支持简单的广播通信,自动通知所有已经订阅过的对象。
- 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
代表案例:看孩子还是打麻将
五、代理模式
代理模式分成两个部分,一个部分是本体; 即为你想要实现的功能;另一部分为代理;代理可以代替本体实例化;
代理一般使用在非常耗时的数据上,也会用在体积十分庞大的本体上。
一句话总结代理模式:为其他对象提供代理,以控制这个对象的访问;
举个简单的例子:
小伙子想要送花给小姑娘,但是不好意思送,于是找到了快递小哥,小哥帮忙送花;在这里小哥就是代理!
//小姑娘(姑娘的名字);
var girl = function(name){
this.name = name;
}
//小伙子(想要送给谁);
var boy = function(girl){
this.girl = girl;
this.sendGift = function(gift){
alert("你好,漂亮的"+this.girl.name+",这是我送你的:"+gift);
}
}
//快递小哥(知道送给谁);
var porxyLitterBrother = function(girl){
this.girl = girl;
this.send = function(gift){
gift = "一个吻";
(new boy(girl)).sendGift(gift);
}
}
现在的送花就变得简单了;
var porxy = new porxyLitterBrother(new girl("花花"));
porxy.send("钻戒");
一个人替你去做一些事情。 这个人保不齐还能捞点好处, 这就是代理模式;
六、适配器模式
//我们要对所有产品都进行一个标准化的测试,测试流程其中包括了
电话、短信、游戏、音乐等等功能
//但是对于一个平板来说,电话功能是无法使用的,因此测试会出问题。
所以将平板进行了包装(类似于代理)
//这样就简单的解决了兼容问题
function test(product) {
try {
product.phonecall();
} catch(e) {
console.log("电话功能测试失败!")
}
try {
product.playgame();
} catch(e) {
console.log("游戏功能测试失败!")
}
}
function Phone(){
this.phonecall = function(){}
this.playgame = function(){}
this.toString = function(){
return "电话";
}
}
function Pad(){
this.playgame = function(){}
this.toString = function(){
return "平板";
}
}
//适配器的意义,多数应用在系统接口使用,也就是别人提供了一个功能,但要求传入一个A类型的参数
//而我们手里的数据是B类型的,如果我们想使用这个功能。那么有两种解决办法:
//第一,把自己的原代码进行修改,让B类型改为A类型,这是非常蠢的做法。
//第二,我们把B类型的数据进行一个包装,让它看起来符合类型A,这个包装函数,就是适配器。
function Adapter(product){
this.phonecall = function(){
if(product.phonecall) {
product.phonecall();
} else {
console.log("this "+ product.toString() + " is not support function phonecall!")
}
}
this.playgame = function(){
if(product.playgame) {
product.playgame();
}
}
}
test(new Phone());
test(new Adapter(new Pad()));
七、抽象工厂模式
7.1 什么是工厂模式
产出对象,创建类的一种设计模式。
7.2 为什么要用工厂模式
当有需求要大量出产相似对象的时候需要用到工厂模式。
7.3 工厂模式怎么用
创建对象使用的设计模式, 主要分成原料,加工和出厂三个部分。
// 想要创建一个对象,对象名为car;
var car = {};
// 想要对car进行组装, 有轮子,和发动机。
car.wheel = "15";
car.engine = "V8";
// 一个车对象产生了。
// 我们能看到的对象大概是这样的。
car {
wheel : 15,
engine : V8
}
这就是一个实用的对象,而现在我们需求升级, 我们需要制造出各种各样不同的车,12寸轮廓的,V6发动机的,各种各样的组合,那么怎么出产这样的抽象汽车对象
我们需要有一个模型, 也就是这个模具构建了这个车大概的样子, 类似于一张设计图。 详细的信息我们根据需求在后续事件为其添加内容 。
这种模式,就是所谓的抽象工厂模式。当然工厂模式是有固定的模式的,这个模式大概是这个样子的。
var factory = (function(){
var car = function (wheel,engine){ //内部配置函数,可以提供配置功能。
this.wheel = wheel;
this.engine = engine;
}
return function(wheel , engine){ // 构造器, 负责创建对象。 // 这是对外提供的接口, 负责和外部需求连接。
return new car(wheel,engine);
}
})()