设计模式(Design Pattern)对于软件开发来说其重要性不言而喻,代码可复用、可维护、可扩展一直都是软件工程中的追求!对于我一个学javascript的人来说,理解设计模式似乎有些困难,对仅切图、做少量交互效果的FE甚至可能不会用到,但是当你开始使用Angular/Backbone等框架的时候,就无法避免设计模式、MVC/MVVM这些东西了(反正我是伤脑筋)。

我学设计模式是刚开始接触编程大概三个月的时候,看一本书《大话设计模式》,里面用C#语言来写,我很无语,因为强类型的编程语言对于我这种写弱类型的毛头小子来说,似乎又有困难啊,于是我就学C#基础语法规则去了。。。今年年初我又学了JAVA的基础语法规则。。。然而我的初衷已经被抛弃在一旁,落上了厚厚的灰层。对于自学编程的我来说,不知道学习编程的先后顺序似乎吃亏不少,但是总要有开头的!

以上可直接跳过


先来说一下我对“观察者模式”的个人理解:观察者模式又称“发布-订阅(Publish/Subscribe)模式”,发布与订阅显然是两个不同对象的功能,比如RSS。知乎是一个发布者(发布一些对某方面问题的高赞同解答),我作为一个订阅者(在我的邮箱里面订阅了知乎的相关发布内容),我的同事以及我的老板都订阅了知乎,所以在这个模型中,有一个发布者,有三个订阅者。

在具体编程中,发布者有了新的内容,需要向订阅者推送数据,那么新的内容(state)、订阅者有哪些(observers)就是发布者需要包含的东西,谁订阅了、谁退订了则要对发布者中的订阅者列表进行更新。以下是发布者的相关信息代码解读:

//发布者
function Publisher(){
this.observers = [];
this.state = ""; }
Publisher.prototype.addOb=function(observer){
var flag = false;
for (var i = this.observers.length - 1; i >= 0; i--) {
if(this.observers[i]===observer){
flag=true;
}
};
if(!flag){
this.observers.push(observer);
}
return this;
}
Publisher.prototype.removeOb=function(observer){
var observers = this.observers;
for (var i = 0; i < observers.length; i++) {
if(observers[i]===observer){
observers.splice(i,1);
}
};
return this;
}
Publisher.prototype.notice=function(){
var observers = this.observers;
for (var i = 0; i < observers.length; i++) {
observers[i].update(this.state);
};
}

以上在遍历observers数组的时候,可以使用数组类的filter、forEach等新特性来处理。第三个notice函数表示发布者有了新东西,然后对订阅者列表中的所有人通知他们我有新内容(state)了,你们拿去更新你们的邮箱吧。这里把内容传递给了每一个订阅者的update更新功能。

那么订阅者呢?订阅者很简单,只需要具有一个update功能即可(每一个订阅者update可能不一样,比如我是放进邮箱了,我的同事则将订阅的拿来,并且顺便把旧的删掉了,我的上司则将数据转发到Gmail去了)。下面是订阅者相关信息代码解读:

//订阅者
function Subscribe(){
this.update = function(data){
console.log(data);
};
}

实际上,因为每一个订阅者都有这个update,所以我们通常应该将其添加到构造器的原型上面,当对这个默认的update功能不满足要求的时候,可以为每一个订阅者的实例设置单独的update,比如将这个data发送给别人。最后咱们看看怎么应用。

//实际应用
var oba = new Subscribe(),
obb = new Subscribe(); var pba = new Publisher(); pba.addOb(oba);
pba.addOb(obb); oba.update = function(state){
console.log(state+"hello!");
}
obb.update = function(state){
console.log(state+"world!");
}
pba.state = "open ";
pba.notice();

大家看到,我们在最后对发布者手动设置了它的内容(state)并且要求他发出通知(notice)。在实际项目中,发布者的内容可能是从后台获取的也可能是从前台某地方输入的。然而发布者每次更新内容后又要手动调用通知是不是有点多余呢?既然更新了内容那就肯定要通知别人了啊。那我们就把内容的更新与发出通知进行绑定好了,看下面的代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
//发布者
function Publisher(){
this.observers = [];
var state = ""; //让该内容不能直接访问 //新增两个对于state的操作 获取/更新
this.getState=function(){
return state;
}
this.setState=function(value){
state = value;
this.notice();
} }
Publisher.prototype.addOb=function(observer){
var flag = false;
for (var i = this.observers.length - 1; i >= 0; i--) {
if(this.observers[i]===observer){
flag=true;
}
};
if(!flag){
this.observers.push(observer);
}
return this;
}
Publisher.prototype.removeOb=function(observer){
var observers = this.observers;
for (var i = 0; i < observers.length; i++) {
if(observers[i]===observer){
observers.splice(i,1);
}
};
return this;
}
Publisher.prototype.notice=function(){
var observers = this.observers;
for (var i = 0; i < observers.length; i++) {
observers[i].update(this.getState()); //获取发布者的内容
};
} //订阅者
function Subscribe(){
this.update = function(data){
console.log(data);
};
} //实际应用
var oba = new Subscribe(),
obb = new Subscribe(); var pba = new Publisher(); pba.addOb(oba);
pba.addOb(obb); oba.update = function(state){
console.log(state+"hello!");
}
obb.update = function(state){
console.log(state+"world!");
}
pba.setState("open "); //发布者更新了内容
</script>
</body>
</html>

对于以上的内容,或许并没有跟我们的项目中实际出现的问题有关,那我们就来代入这种设计模式,做一个例子:三个文本框ABC,其中A可编辑,B与C不可编辑且B的值是A的值加上后缀"@w3c.com",C的值是A的值加上前缀"ID-"。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>
<label>用户名称:<input type="text" id="pba" placeholder="请输入用户名称" /></label><br /><br />
<label>生成邮箱:<input type="text" id="oba" readonly /></label>
<label>生成ID:<input type="text" id="obb" readonly /></label>
</div> <script type="text/javascript">
//发布者
function Publisher(obj){
this.observers = [];
var state = obj.value; //让该内容不能直接访问 //新增两个对于state的操作 获取/更新
this.getState=function(){
return state;
}
this.setState=function(value){
state = value;
this.notice();
}
this.obj = obj; }
Publisher.prototype.addOb=function(observer){
var flag = false;
for (var i = this.observers.length - 1; i >= 0; i--) {
if(this.observers[i]===observer){
flag=true;
}
};
if(!flag){
this.observers.push(observer);
}
return this;
}
Publisher.prototype.removeOb=function(observer){
var observers = this.observers;
for (var i = 0; i < observers.length; i++) {
if(observers[i]===observer){
observers.splice(i,1);
}
};
return this;
}
Publisher.prototype.notice=function(){
var observers = this.observers;
for (var i = 0; i < observers.length; i++) {
observers[i].update(this.getState());
};
} //订阅者
function Subscribe(obj){
this.obj = obj;
this.update = function(data){
this.obj.value = data;
};
} //实际应用
var oba = new Subscribe(document.querySelector("#oba")),
obb = new Subscribe(document.querySelector("#obb")); var pba = new Publisher(document.querySelector("#pba")); pba.addOb(oba);
pba.addOb(obb); oba.update = function(state){
this.obj.value = state+"@w3c.com";
}
obb.update = function(state){
this.obj.value = "ID-"+state;
} pba.obj.addEventListener('keyup',function(){
pba.setState(this.value);
}); </script>
</body>
</html>

在《大话设计模式》一书中,提到类似的情况:如果针对发布者内容而订阅者要做不同的事情呢?比如一个按钮和三个矩形,点击按钮的时候,第一个矩形增加宽度,第二个矩形增加高度,第三个矩形则变成圆角矩形又该怎么做呢?当然我们可以在三个矩形的update内部写具体的实现代码,但是这update岂不是没有一个具体的功能描述了吗?该书中用“事件委托”解决了这个问题(此处事件委托和DOM中的事件委托应该是两码事),我个人理解这个“事件委托”在javascript中可以用一个数组表示,然后里面放各个订阅者的不同名字的update,然后一一调用。

在《javascript设计模式》一书中,关于观察者模式的实现也是采用”推“这种方式,章节的最后反问到如何实现”拉“这种方式呢?

我个人理解:发布者推送数据的时候有强制性,促使订阅者更新(update),然而在”拉“这种模式中,发布者本身仅仅包含最新的内容,没有通知(notice)没有订阅者列表,当订阅者需要得到数据的时候在其对应的update方法里面传入发布者对象即可。小白之见,请对该模式有不同理解的道友多多指正。o(∩_∩)o

JavaScript设计模式之观察者模式(学习笔记)的更多相关文章

  1. [GeekBand] 设计模式之观察者模式学习笔记

    本文参考文献::GeekBand课堂内容,授课老师:李建忠 :网络资料: http://blog.csdn.net/hguisu/article/details/7556625 本文仅作为自己的学习笔 ...

  2. 《零基础学JavaScript(全彩版)》学习笔记

    <零基础学JavaScript(全彩版)>学习笔记 二〇一九年二月九日星期六0时9分 前期: 刚刚学完<零基础学HTML5+CSS3(全彩版)>,准备开始学习JavaScrip ...

  3. 再起航,我的学习笔记之JavaScript设计模式18(观察者模式)

    观察者模式 观察者模式(Observer): 又被称为发布-订阅者模式或消息机制,定义了一种依赖关系,解决了主体对象与观察者之间功能的耦合. 创建一个观察者对象 首先我们创建一个闭包对象,让其在页面加 ...

  4. 《JavaScript语言精粹》学习笔记

    一.in的用法 for...in 枚举一个对象的所有可枚举属性 检测DOM/BOM属性 if ("onclick" in elem) { // 元素支持onclick } if ( ...

  5. 《JavaScript高级程序设计》学习笔记12篇

    写在前面: 这12篇博文不是给人看的,而是用来查的,忘记了什么基础知识,点开页面Ctrl + F关键字就好了 P.S.如果在对应分类里没有找到,麻烦告诉我,以便尽快添上.当然,我也会时不时地添点遗漏的 ...

  6. 《JavaScript权威指南》学习笔记 第六天 开始学习DOM了。

    昨天学习了window对象的一些方法.window对象主要是针对当前视窗的操作.window对象提供了一些列API来帮助我们了解当前窗口的信息.例如history对象可以让我们获取浏览历史.nvaig ...

  7. Ruby设计模式-观察者模式学习笔记

    observer.rb #!/bin/env ruby # encoding: utf-8 require 'observer' class CriminalMovement include Obse ...

  8. 《JavaScript高级程序设计》学习笔记(5)——面向对象编程

    欢迎关注本人的微信公众号"前端小填填",专注前端技术的基础和项目开发的学习. 本节内容对应<JavaScript高级程序设计>的第六章内容. 1.面向对象(Object ...

  9. 《JavaScript权威指南》学习笔记 第五天 window对象的方法。

    前天和昨天大致浏览了犀牛书的函数.类与模块.正则表达式.JavaScript扩展.以及服务端的js.这些方面对于我目前的水平来说比较难,一些最基本的概念都不能领会.不过最复杂的知识占用平时使用的20% ...

随机推荐

  1. const 笔记

    .指向const的指针例如:double a=1.01;const double * b=&a;*b=2.1; //这显然是错误的a=2.1; //这是正确的,a和*b的值都会变成2.01,有 ...

  2. net programming guid

    Beej's Guide to Network Programming Using Internet Sockets Brian "Beej Jorgensen" Hallbeej ...

  3. Web工程软件升级之数据库升级(一)

    1. 首先检查oracle数据库版本是否正确 (可以使用方法 lsinventory来实现) 2. 检查oracle连接是否成功 3. 解压升级包,放到特定目录 4. 做升级前数据备份,备份主要业务数 ...

  4. 解决Ext.TextField的AllowBlank不能过滤空格代码

    Ext过滤空格 重写了组件... Ext.apply(Ext.form.TextField.prototype, { validator : function(text) { if (this.all ...

  5. 获取Delphi所有类的类信息

    Delphi遍历进程中所有Class的TypeInfo,即便是在implementation中的class或者其他 class的private的子class. 一般普通EXE中的TypeInfo存放在 ...

  6. java中String s="abc"及String s=new String("abc")详解

    1.   栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2.   栈的优势是,存取速度比堆要快,仅次于直 ...

  7. 【HDOJ】1818 It's not a Bug, It's a Feature!

    状态压缩+优先级bfs. /* 1818 */ #include <iostream> #include <queue> #include <cstdio> #in ...

  8. POJ1416 Shredding Company(dfs)

    题目链接. 分析: 这题从早上调到现在.也不算太麻烦,细节吧. 每个数字都只有两种状态,加入前一序列和不加入前一序列.DFS枚举. #include <iostream> #include ...

  9. 【转】如何在github上fork一个项目来贡献代码以及同步原作者的修改 -- 不错

    原文网址:http://www.cnblogs.com/astwish/articles/3548844.html 作为一个IT人,通过github进行学习是最快的成长手段.我们可以浏览别人的优秀代码 ...

  10. github继续折腾

    又在折腾github了,本来以前在neworiginou这个github上上传过项目的: 现在想在另一个github上joely上传项目,发现按以前的流程做个测试,居然没能上传成功! 经发现,以前的n ...