Javascript的设计模式

什么是设计模式

  • 单体模式:
  • 工厂模式:
  • 观察者模式(发布订阅模式)
  • 策略模式
  • 模板模式
  • 代理模式
  • 外观模式

设计模式太多了,貌似有23种,其实我们在平时的工作中没有必要特意去用什么样的设计模式,或者你在不经意间就已经用了设计模式当中的一种。本文旨在总结平时相对来说用的比较多的设计模式。

什么是设计模式

  设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

  使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

工厂模式

工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。

单体模式

单体模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一变量进行访问。

单体模式的优点是:

  • 可以用来划分命名空间,减少全局变量的数量。
  • 使用单体模式可以使代码组织的更为一致,使代码容易阅读和维护。
  • 可以被实例化,且实例化一次。
  • 什么是单体模式?单体模式是一个用来划分命名空间并将一批属性和方法组织在一起的对象,如果它可以被实例化,那么它只能被实例化一次。

但是并非所有的对象字面量都是单体,比如说模拟数组或

模块模式

我们通过单体模式理解了是以对象字面量的方式来创建单体模式的;比如如下的对象字面量的方式代码如下:

var singleMode = {
    name: value,
    method: function(){

    }
};

模块模式的思路是为单体模式添加私有变量和私有方法,能够减少全局变量的使用;如下就是一个模块模式的代码结构:

var singleMode = (function(){
    // 创建私有变量
    var privateNum = 112;
    // 创建私有函数
    function privateFunc(){
        // 实现自己的业务逻辑代码
    }
    // 返回一个对象包含公有方法和属性
    return {
        publicMethod1: publicMethod1,
        publicMethod2: publicMethod1
    };
})();

模块模式使用了一个返回对象的匿名函数。在这个匿名函数内部,先定义了私有变量和函数,供内部函数使用,然后将一个对象字面量作为函数的值返回,返回的对象字面量中只包含可以公开的属性和方法。这样的话,可以提供外部使用该方法;由于该返回对象中的公有方法是在匿名函数内部定义的,因此它可以访问内部的私有变量和函数。

除了命名空间模式,也可以使用闭包的特性来模拟实现私有成员的功能来提升安全性,这里可以通过 IIFE 快速创建一个闭包,将要隐藏的变量和方法放在闭包中,这就是模块模式。
https://blog.csdn.net/weixin_40629244/article/details/103505949

我们什么时候使用模块模式?

如果我们必须创建一个对象并以某些数据进行初始化,同时还要公开一些能够访问这些私有数据的方法,那么我们这个时候就可以使用模块模式了。

发布订阅模式

发布—订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。

https://www.zhihu.com/question/23486749

几种实现双向绑定的做法

目前几种主流的mvc(vm)框架都实现了单向数据绑定,而我所理解的双向数据绑定无非就是在单向绑定的基础上给可输入元素(input、textare等)添加了change(input)事件,来动态修改model和 view,并没有多高深。所以无需太过介怀是实现的单向或双向绑定。

实现数据绑定的做法有大致如下几种:

  • 发布者-订阅者模式(backbone.js)

  • 脏值检查(angular.js)

  • 数据劫持(vue.js)

发布者-订阅者模式:

一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set(‘property’, value),
这种方式现在毕竟太low了,我们更希望通过 vm.property = value 这种方式更新数据,同时自动更新视图,于是有了下面两种方式

脏值检查:

angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:

  • DOM事件,譬如用户输入文本,点击按钮等。( ng-click )

  • XHR响应事件 ( $http )

  • 浏览器Location变更事件 ( $location )

  • Timer事件( $timeout , $interval )

  • 执行 $digest() 或 $apply()

数据劫持:

vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

Object.defineProperty

顾名思义,为对象定义属性。在js中我们可以通过下面这几种方法定义属性

// (1) define someOne property name
someOne.name = 'cover';
//or use (2) 
someOne['name'] = 'cover';
// or use (3) defineProperty
Object.defineProperty(someOne, 'name', {
    value : 'cover'
})

从上面看,貌似使用Object.defineProperty很麻烦,那为啥存在这样的方法呢?

带着疑问,我们来看下 Object.defineProperty的定义。

what is Object.defineProperty
The Object.defineProperty() method defines a new property directly on an object, or modifies an exisiting property on an object, and returns the object.

从上面得知,我们可以通过Object.defineProperty这个方法,直接在一个对象上定义一个新的属性,或者是修改已存在的属性。最终这个方法会返回该对象。

注意 在调用Object.defineProperty()方法时,如果不指定, configurable, enumerable, writable特性的默认值都是false,

这跟之前所 说的对于像前面例子中直接在对象上定义的属性,这个特性默认值为为 true。并不冲突,如下代码所示:

//直接在对象上定义的属性,这个特性默认值为为 true

    var someOne = { };
    someOne.name = 'coverguo';
    console.log(Object.getOwnPropertyDescriptor(someOne, 'name'));
    //输出 Object {value: "coverguo", writable: true, enumerable: true, configurable: true}


    //调用Object.defineProperty()方法时,如果不指定,特性默认值为为 false
    var otherOne = {};
    Object.defineProperty(otherOne, "name", {
            value:"coverguo" 
    });  
    console.log(Object.getOwnPropertyDescriptor(otherOne, 'name'));
    //输出 Object {value: "coverguo", writable: false, enumerable: false, configurable: false}

实际运用
在一些框架,如vue、express、qjs等,经常会看到对Object.defineProperty的使用。那这些框架是如何使用呢?

MVVM中数据‘双向绑定’实现

一些算法

总结

工厂模式(Factory)

工厂模式:工厂模式就是利用一个工厂对象(方法),来生成需要的对象,避免了直接使用new+构造函数的方式来生成对象,同时工厂方法生成目标对象的过程可以自由控制,来按需生成对象。

特点:

目的是为了生成对象
控制生成过程,按需生成

单例模式(singleton)

单例模式是指严格约束一个类只有一个实例对象。

一个典型的单例模式可以这样实现,通过一个方法来生成单例对象,当该对象不存在时,生成对象并返回,当对象存在时,直接返回对象。

js中,单例模式通常与namespace的实现联系在一起,利用namespace来为单例对象提供一个全局统一的获取入口,而单例对象作为一个闭包对象存储在namespace中。

观察者模式(Observe)

观察者模式指的是一个对象(Subject)维持一系列依赖于它的对象(Observer),当有关状态发生变更时 Subject 对象则通知一系列 Observer 对象进行更新。

观察者模式中存在两种关键对象以及三种关键操作

subject对象:维护一系列的观察者对象,提供三种基本操作方式:被订阅(注册监听方法 register),被取消订阅(移除监听方法 remove),触发事件(trigger)。

observers对象:业务逻辑执行对象,监听subject对象触发的事件。

观察者模式非常有利于对象之间的解耦

发布订阅模式(Publish/Subscribe)

发布订阅者模式的两种对象和三个关键方法:

publisher:维护一系列的subscriber对象,提供三种基本操作方式:

被订阅(注册监听方法 subscribe(event, handler)),被取消订阅(移除监听方法 unsubscribe(event, handler)),触发事件(publish(event))。

subscribers:相当于原来的observer对象,通过监听事件进行业务处理

发布订阅模式指的是希望接收通知的对象(Subscriber)通过自定义事件订阅主题,被激活事件的对象(Publisher)通过发布主题事件的方式通知各个订阅该主题的 Subscriber 对象。

观察者模式与发布订阅模式都是定义了一个一对多的依赖关系,当有关状态发生变更时则执行相应的更新。

不同的是,在观察者模式中依赖于 Subject 对象的一系列 Observer 对象在被通知之后只能执行同一个特定的更新方法,而在发布订阅模式中则可以基于不同的主题去执行不同的自定义事件。相对而言,发布订阅模式比观察者模式要更加灵活多变。

https://www.cnblogs.com/yongwunaci/p/12021194.html