模式有三种:Architectural Pattern、Design Pattern、Coding Pattern,即:框架模式、设计模式、编程模式。本文主要讲解javascript中的设计模式,好的设计模式能够提高代码的重用性,可读性,使代码更容易的维护和扩展。本文适合有一点javascript基础,对javascript的概念有所了解。

一、单例模式:

单例模式是javascript中最常用的模式,它是将自己的代码放在一个命名空间下,这样的好处是可以减少使用全局变量,在多人协同开发时也能避免命名冲突等问题。这样的好处是维护起来非常方便,如下例:

 var m = {
name: 'dog',
action: function() {
console.log(this.name);
}
};
m.action();//调用

或者

 var dog = function() {
this.name = 'dog';
this.action = function() {
return console.log(this.name);
};
action();
};
dog(); //调用

工厂模式:

工厂模式就是将对象的方法创建交给外部对象,这样的好处就是解决了对象之间的相互影响、即耦合,避免了使用new来实例化对象,有助于创建模块化的代码,维护起来也方便。 工厂模式分为简单工厂模式和抽象工厂模式,下面介绍简单工厂模式:

 var m = {};
m.action = function() {
console.log('dog');
};
var demo = function() {
m.action();
};
demo()//调用

抽象工厂模式先设计一个抽象类,这个类不能被实例化,只能用来派生子类,最后通过对子类的扩展实现工厂方法。如下:

 var f = function() {};
f.prototype = {
c: function() {
throw new Error('can\'t use this method');//如果调用此方法会报错,因为它是用来派生子类不能实例化
}
};
var e = function() {
f.call(this);
}
e.prototype = new f();
e.prototype.constructor = e;
e.prototype.c = function() {
console.log('this method is redefine');
}
// 调用
var demo = new e();
demo.c();

桥接模式:

桥接模式是将抽象与实现隔离,一遍二者独立变化。在设计一个javascript API的时候,它可以用来弱化类和对象之间的耦合。它还可以用来把多个类联接在一起。例如:

 var class1 = function(a,b,c) {
this.a = a;
this.b = b;
this.c = c;
};
var class2 = function(d) {
this.d = d;
};
var demo = function(a,b,c,d) {
this.one = new Class1(a,b,c);
this.two = new Class2(d);
};

组合模式:

组合模式可以用一条命令在多个对象上激发复杂的或递归的行为。好处是可以用同样的发放处理对象的集合与其中的特定子对象,也可以用来把一批子对象组织成树形结构,并且使整个树都可被遍历。如下:

 // DynamicGallery Class
  var DynamicGallery =function (id) { // 实现Composite,GalleryItem组合对象类
  this.children = [];
  this.element = document.createElement('div');
  this.element.id = id;
  this.element.className ='dynamic-gallery';
  }
  DynamicGallery.prototype = {
  // 实现Composite组合对象接口
  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) {
  returnthis.children[i];
  },
  // 实现DynamicGallery组合对象接口
  hide: function () {
  for (var node, i =0; node =this.getChild(i); i++) {
  node.hide();
  }
  this.element.style.display ='none';
  },
  show: function () {
  this.element.style.display ='block';
  for (var node, i =0; node = getChild(i); i++) {
  node.show();
  }
  },
  // 帮助方法
  getElement: function () {
  returnthis.element;
  }
  }
 var GalleryImage =function (src) { // 实现Composite和GalleryItem组合对象中所定义的方法
  this.element = document.createElement('img');
  this.element.className ='gallery-image';
  this.element.src = src;
  }
  GalleryImage.prototype = {
  // 实现Composite接口
  // 这些是叶结点,所以我们不用实现这些方法,我们只需要定义即可
  add: function () { },
  remove: function () { },
  getChild: function () { },
  // 实现GalleryItem接口
  hide: function () {
  this.element.style.display ='none';
  },
  show: function () {
  this.element.style.display ='';
  },
  // 帮助方法
  getElement: function () {
  returnthis.element;
  }
  }
 var topGallery =new DynamicGallery('top-gallery');
  topGallery.add(new GalleryImage('/img/image-1.jpg'));
  topGallery.add(new GalleryImage('/img/image-2.jpg'));
  topGallery.add(new GalleryImage('/img/image-3.jpg'));
  var vacationPhotos =new DyamicGallery('vacation-photos');
  for(var i =0, i <30; i++){
    vacationPhotos.add(new GalleryImage('/img/vac/image-'+ i +'.jpg'));
  }
  topGallery.add(vacationPhotos);
  topGallery.show();
  vacationPhotos.hide();

门面模式:

门面模式常常是开发人员最亲密的朋友,他几乎是所有javascript库的核心原则。门面模式有两个作用:一是简化类的接口;二是消除类与使用它的客户代码之间的耦合。示例如下:

 function a() {

 }
function b() { }
function ab() {
a();
b();
}

适配器模式:

适配器模式可以用来在现有接口和不兼容的类之间进行适配。从表面上看,适配器模式很像门面模式,都对别的对象进行包装并改变其呈现的接口。二者的区别在与它们如何改变接口,门面元素展现的是一个简化的接口,它并不提供额外的选择,而且有时为了方便完成常见任务它还会做出一些假定。而适配器则要把一个接口转换为另一个接口,它并不会过滤某些能力,也不会简化接口。

 var str = {
a: 'a',
b: 'b',
c: 'c'
};
function i(s1,s2,s3) {
console.log(s1 + ',' + s2 + ',' + s3);
}
function demo(o) {
i(o.a,o.b,o.c);
}

装饰者模式:

装饰者模式可用来透明地把对象包装在具有同样接口的另一个对象之中,装饰者可以用于为对象添加功能,可以用来代替大量子类。装饰者模式和组合模式有很多共同点,它们都与所包装的对象实现统一的接口并且会把任何方法条用传递给这些对象。可是组合模式用于把众多子对象组织为一个整体,而装饰者模式用于在不修改现有对象或从派生子类的前提下为其添加方法。如下:

 var m = {};
m.child = {};
m.child.one = function() {};
m.child.two = function() {};

享元模式:

享元模式最适合于解决因创建大量类似对象而累及性能的问题。通过把大量独立对象转化为少量共享对象,可以降低运行web应用程序所需的资源数量。

javascript设计模式中的示例:

 //汽车登记示例
  var Car =function(make,model,year,owner,tag,renewDate){
    this.make=make;
    this.model=model;
    this.year=year;
    this.owner=owner;
    this.tag=tag;
    this.renewDate=renewDate;
  }
  Car.prototype = {
    getMake:function(){
      returnthis.make;
    },
    getModel:function(){
      returnthis.model;
    },
    getYear:function(){
      returnthis.year;
    },
    transferOwner:function(owner,tag,renewDate){
      this.owner=owner;
      this.tag=tag;
      this.renewDate=renewDate;
    },
    renewRegistration:function(renewDate){
      this.renewDate=renewDate;
    }
  }
  //数据量小到没多大的影响,数据量大的时候对计算机内存会产生压力,下面介绍享元模式优化后
  //包含核心数据的Car类
  var Car=function(make,model,year){
    this.make=make;
    this.model=model;
    this.year=year;
  }
  Car.prototype={
    getMake:function(){
      returnthis.make;
    },
    getModel:function(){
      returnthis.model;
    },
    getYear:function(){
      returnthis.year;
    }
  }
  //中间对象,用来实例化Car类
  var CarFactory=(function(){
    var createdCars = {};
    return {
      createCar:function(make,model,year){
        var car=createdCars[make+"-"+model+"-"+year];
        return car ? car : createdCars[make +'-'+ model +'-'+ year] =(new Car(make,model,year));
      }
    }
  })();
  //数据工厂,用来处理Car的实例化和整合附加数据
  var CarRecordManager = (function() {
    var carRecordDatabase = {};
    return {
      addCarRecord:function(make,model,year,owner,tag,renewDate){
        var car = CarFactory.createCar(make, model, year);
        carRecordDatabase[tag]={
          owner:owner,
          tag:tag,
          renewDate:renewDate,
          car:car
      }
    },
      transferOwnership:function(tag, newOwner, newTag, newRenewDate){
        var record=carRecordDatabase[tag];
        record.owner = newOwner;
        record.tag = newTag;
        record.renewDate = newRenewDate;
      },
      renewRegistration:function(tag,newRenewDate){
        carRecordDatabase[tag].renewDate=newRenewDate;
      },
      getCarInfo:function(tag){
        return carRecordDatabase[tag];
      }
    }
  })();

代理模式:

代理是一个对象,它可以用来控制对另一个对象的访问。它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象。代理模式适合处理实例化比较费时的本体,也适合处理那些需要较长时间才能把数据载入用户界面的类。

javascript设计模式中的示例:

 var Publication =new Interface('Publication', ['getIsbn', 'setIsbn', 'getTitle', 'setTitle', 'getAuthor', 'setAuthor', 'display']);
  var Book =function(isbn, title, author) {
   //...
  }
  // implements Publication
  implements(Book,Publication);   /* Library interface. */
  var Library =new Interface('Library', ['findBooks', 'checkoutBook', 'returnBook']);   /* PublicLibrary class. */
  var PublicLibrary =function(books) {
   //...
  };
  // implements Library
  implements(PublicLibrary,Library);   PublicLibrary.prototype = {
   findBooks: function(searchString) {
   //...
  },
  checkoutBook: function(book) {
   //...
   },
  returnBook: function(book) {
   //...
   }
  };   /* PublicLibraryProxy class, a useless proxy. */
  var PublicLibraryProxy =function(catalog) {
   this.library =new PublicLibrary(catalog);
  };
  // implements Library
  implements(PublicLibraryProxy,Library);   PublicLibraryProxy.prototype = {
   findBooks: function(searchString) {
   returnthis.library.findBooks(searchString);
  },
  checkoutBook: function(book) {
   returnthis.library.checkoutBook(book);
   },
   returnBook: function(book) {
   returnthis.library.returnBook(book);
   }
  };

观察者模式:

观察者模式是一种管理人与其任务之间的关系的得力工具。观察者模式中存在两个角色:观察者和被观察者。这种模式的好处是你可以对程序中某个对象的状态进行观察,并且在其发生改变时能够得到通知。

   var f1 =function(){
  //code
  }
  var f2 =function(){
  //code
  }
  addEvent(element,'click',f1);
  addEvent(element,'click',f2)   element.onclick = f1;
  element.onclick = f2;

命令模式:

命令模式可以用来对方法调用进行参数化处理和传送,经这样处理过的方法调用可以在任何需要的时候执行。好处是可以用来消除调用操作的对象和实现操作的对象之间的耦合,使对象间的互动方式更高的模块化。这为各种具体的类更换带来了极大的灵活性。

 car Calculator={
  add:function(x,y){
   return x+y;
  },
  substract:function(x,y){
   return x-y;
  },
  multiply:function(x,y){
   return x*y;
  },
  divide:function(x,y){
   return x/y;
  }
  }
  Calculator.calc =function(command){
  return Calculator[command.type](command.op1,command.opd2)
  };
  Calculator.calc({type:'add',op1:1,op2:1});
  Calculator.calc({type:'substract',op1:5,op2:2});
  Calculator.calc({type:'multiply',op1:5,op2:2});
  Calculator.calc({type:'divide',op1:8,op2:4});

职责链模式:

职责链模式是通过实现一个由隐式地请求进行处理对象组成的链而做到的。可以用来消除请求的发送者和接收者之间的耦合

javascript内部就使用了这种模式来处理事件捕获和冒泡的问题。

职责链由多个不同类型的对象组成:发送者是发出请求的对象,而接收者则是接收请求并且对其进行处理或传递的对象,请求本身有时也是一个对象,它封装着与操作有关的所有数据。其典型的流程大致是:

  1. 发送者知道链中第一个接收者,它向这个接收者发出请求。
  2. 每一个接收者都对请求进行分析,然后要么处理它,要么将其往下传。
  3. 每一个接收者知道的其他对象只有一个,即它在链中的下家。
  4. 如果没有任何接收者处理请求,那么请求将从链上离开,不同的实现对此也有不同的反应,一般会抛出一个错误。

小结:

  每种模式都有自己的优点,选择一种适合自己业务的模式非常重要,能够提高代码的可读性、可维护性等等,希望本文能够对你有所帮助。

本文参考电子书《javascript设计模式》

模式(一)javascript设计模式的更多相关文章

  1. JavaScript设计模式与开发实践 - 观察者模式

    概述 观察者模式又叫发布 - 订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个目标对象(为了方便理解,以下将观察者对象叫做订阅者,将目标对象叫做 ...

  2. Javascript设计模式笔记

    Javascript是越来越厉害了,一统前后端开发.于是最近把设计模式又看了一遍,顺便做了个笔记,以方便自己和他人共同学习. 笔记连载详见:http://www.meteorcn.net/wordpr ...

  3. javascript 设计模式-----策略模式

    在<javascript设计模式>中,作者并没有向我们介绍策略模式,然而它却是一种在开发中十分常见的设计模式.最常见的就是当我们遇到一个复杂的表单验证的时候,常常需要编写一大段的if和el ...

  4. Javascript设计模式之我见:状态模式

    大家好!本文介绍状态模式及其在Javascript中的应用. 模式介绍 定义 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是控制一个对象状态的条件表达式 ...

  5. Javascript设计模式之我见:迭代器模式

    大家好!本文介绍迭代器模式及其在Javascript中的应用. 模式介绍 定义 提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象内部表示. 类图及说明 Iterator抽象迭代器 抽象迭代器负 ...

  6. JavaScript设计模式 - 迭代器模式

    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  7. JavaScript设计模式 - 代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问 代理模式的用处(个人理解):为了保障当前对象的单一职责(相对独立性),而需要创建另一个对象来处理调用当前对象之前的一些逻辑以提高代码的效 ...

  8. 【读书笔记】读《JavaScript设计模式》之代理模式

    一.定义 代理是一个对象,它可以用来控制对另一个对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替其实体被实例化,并使其可被远程访 ...

  9. 【读书笔记】读《JavaScript设计模式》之装饰者模式

    一.定义 装饰者模式可用来透明地把对象包装在具有同样接口的另一个对象之中.这样一来,你可以给一个方法添加一些行为,然后将方法调用传递给原始对象.相对于创建子类来说,使用装饰者对象是一种更灵活的选择(装 ...

  10. 【读书笔记】读《JavaScript设计模式》之门面模式

    一.前言 门面模式,也称Facade(外观)模式.核心的两点作用—— 1> 简化类的接口(让接口变得更加容易理解.容易应用.更加符合对应业务),来掩盖一个非常不同或者复杂的实现 2> 消除 ...

随机推荐

  1. OPC UA

    OPC UA将来自不同厂商不同设备的数据进行统一格式.统一显示. OPC: originally knowns as “OLE for Process Control”, now “Open Plat ...

  2. 无线linux应用及配置--wifi配置

    linux下应用wifi,AP侧运行程序hostapd,客户端运行wpa_supplicant.官网:http://w1.fi/. 无线网卡应用 无线网卡的应用服务程序为wpa_supplicant, ...

  3. windows 下 MySql5.6主从复制

    说明: 1.MySql 版本5.6 2.本例中使用的主从服务器ip分别为:192.168.120.211:192.168.120.209 一.配置master服务器 1.配置 在my.ini中[mys ...

  4. c# 自定义类型的DataBindings

    自定义类型TextBoxEx,扩展了TextBox,增加了一个属性KeyText来保存后台的值(Tag已另作它用). 程序里面需要将KeyText和DataTable的某个列绑定起来. 如果是Text ...

  5. 25个最常用的iptables策略

    1.清空存在的策略当你开始创建新的策略,你可能想清除所有的默认策略,和存在的策略,可以这么做:iptables -F  或者iptables --flush2,设置默认策略默认链策略是ACCEPT,改 ...

  6. Spring Cloud搭建手册(2)——Spring Cloud Config

    ※在Dalston.SR2版本以后,均不能正常加密,如果必须使用此功能,需要降级到SR1或Camden SR7. 1.首先需要创建一个config-server工程,作为配置中心的服务器,用来与git ...

  7. PCL点云特征描述与提取(3)

    快速点特征直方图(FPFH)描述子 已知点云P中有n个点,那么它的点特征直方图(PFH)的理论计算复杂度是,其中k是点云P中每个点p计算特征向量时考虑的邻域数量.对于实时应用或接近实时应用中,密集点云 ...

  8. Matlab查看数值不用科学计数法显示

    如图: 运行结果显示的是科学计数法的数据 输入命令“format long g”  -->  Enter -->  输入需要转换的数据 即可显示.

  9. python——读取MATLAB数据文件 *.mat

    鉴于以后的目标主要是利用现有的Matlab数据(.mat或者.txt),主要考虑python导入Matlab数据的问题.以下代码可以解决python读取.mat文件的问题.主要使用sicpy.io即可 ...

  10. Qt中如何根据类名来实例化对象

    对于Qt 来说,是可以做到运行时,根据对象的类名字(字符串)来获得对象的实例的,这点和一些语言的反射机制是一样的. 但是在Qt中,我们需要所额外的一步,就是注册.只要做到了注册,我们就可以 自由的创建 ...