JavaScript设计模式

设计模式:

什么是设计模式:

是一套经过反复使用、多人知晓的、经过分类的、代码设计经验的总结

为什么使用设计模式:

为了代码的可重用性、让代码更容易被他人理解、保证代码的可靠性。设计模式使代码的编写真正的工程化;设计模式是软件工程的基石脉络,如同大厦的结构

有哪些设计模式(来自W3school,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),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。

使用观察者模式的好处:

  • 支持简单的广播通信,自动通知所有已经订阅过的对象。

  • 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。

  • 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

    代表案例:看孩子还是打麻将

//		发布订阅者:
//			发布者:实时发布或更新信息
//			订阅者:接收到信息,根据信息作出对应的反映或处理

//		一对多的关系
//		实现广播通信
//		耦合低

function Child(n){
	this.name = n;
	this.type = function(){
		return Math.random() > 0.5 ? 0 : 1;
	}
}

function Parent(n,c){
	this.child = c
	this.name = n;
	this.listen = function(type){
		if(type == 0){
			console.log(c.name + "哭了",this.name + "去喂奶");
		}else{
			console.log(c.name + "睡了",this.name + "打麻将");
		}
	}
}

var c = new Child("大宝");
var t = c.type();
var p1 = new Parent("大宝爸",c);
var p2 = new Parent("大宝妈",c);
var p3 = new Parent("大宝家的保姆",c);

p1.listen(t);
p2.listen(t);
p3.listen(t);

MVC模式(扩展)

MVC模式,全名:Model View Controller,模型 视图 控制器
视图:用户直观看到的页面
模型:按照要求来取出数据
控制器:向系统发出指令的工具

//		MVC:
//			Model:模型
//			View:视图
//			Ctrl:控制器
//		用户给c传递指令
//		c根据指令,找m,要数据
//		m根据c的指令返回指定的数据
//		c拿到数据,保存,然后根据指令找v
//		找v的同时将m给打数据,发给v
//		v负责将数据渲染

class Model{
	mymodel1(){
		return "hello,这是第一个数据";
	}
	mymodel2(){
		return "hi,这是第二个数据";
	}
	mymodel3(){
		return "你好,这是第三个数据";
	}
}

class View{
	myview1(data){
		console.log(data)
	}
	myview2(data){
		alert(data)
	}
	myview3(data){
		document.write(data)
	}
}

class Ctrl{
	constructor(){
		this.m = new Model();
		this.v = new View();
	}
	myctrl1(){
		this.d = this.m.mymodel3();
		this.v.myview2(this.d);
	}
	myctrl2(){
		this.d = this.m.mymodel1();
		this.v.myview3(this.d);
	}
	myctrl3(){
		this.d = this.m.mymodel2();
		this.v.myview1(this.d);
	}
}

var c = new Ctrl();
c.myctrl1();
c.myctrl2();
c.myctrl3();

代理模式

代理模式分成两个部分,一个部分是本体; 即为你想要实现的功能;另一部分为代理;代理可以代替本体实例化;
代理一般使用在非常耗时的数据上,也会用在体积十分庞大的本体上。

一句话总结代理模式:为其他对象提供代理,以控制这个对象的访问;

举个简单的例子:

小伙子想要送花给小姑娘,但是不好意思送,于是找到了快递小哥,小哥帮忙送花;在这里小哥就是代理!

//小姑娘(姑娘的名字);
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("钻戒");

一个人替你去做一些事情。 这个人保不齐还能捞点好处, 这就是代理模式;

适配器模式

拓展:

    try{
        可能要报错的代码
    }catch(e){
        如果报错,执行此处代码
    }

我们要对所有产品都进行一个标准化的测试,测试流程其中包括了
电话、短信、游戏、音乐等等功能

但是对于一个平板来说,电话功能是无法使用的,因此测试会出问题。
所以将平板进行了包装(类似于代理)

//这样就简单的解决了兼容问题
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()));

抽象工厂模式

什么是工厂模式?
产出对象,创建类的一种设计模式。

为什么要用工厂模式?
当有需求要大量出产相似对象的时候需要用到工厂模式。

工厂模式怎么用?
创建对象使用的设计模式, 主要分成原料,加工和出厂三个部分。

想要创建一个对象,对象名为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);
    }
})()

策略模式

//		策略模式:
//			策略:计划

//		0:学习
//		1:出去玩
//		2:睡觉
//		3:打游戏

var type = 0;

if(type == 0){
//	学习
}else if(type == 1){
//	出去玩
}else if(){
	
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值