>[success] # 书中的登录案例 ~~~ 1.书中举了一个例子 :假如我们正在开发一个商城网站,网站里有 header 头部、 nav 导航、消息列表、购物车等模,这几个模块的渲染有一个共同的前提条件, 就是必须先用 ajax 异步请求获取用户的登录信息。 2.上面的场景就是一对多,一就是登陆接口返回的数据,对应多个需要他的地方 3.将这个场景转换成发布订阅模式,一个用来保存订阅者缓存的发布者对象,一个 执行发布消息触发的地方 ~~~ >[danger] ##### 不使用发布订阅模式代码写法如下 ~~~ 1.当登陆成功的时候需要执行四个地方,分别是导航头像,header标签里的头像, 刷新消息列表,刷新购物车,这种写法在工作中很常见,'js设计模式与开发的作者' 提出了两个场景让这种常见的写法变得直击心灵 1.1 如果当后续其他开发人员增加了一个收货模块,需要在获取用户信息的时候加载一下 就需要找到最开始写这个登录接口的人,告诉他在这个'login.succ'中接着添加一个收货 模块的加载 1.2.这种开发模式叫'针对具体实现编程'书中作者对这类的编程不赞同,会出现另外一个问题, 假如你是开发登录模块,但你的登陆模块出现了现在的问题需要加载其他模块的方法,你 就需要了解解 header 模块里设置头像的方法叫setAvatar、购物车模块里刷新的方法叫 refresh, 不仅如此你还不能随意改变setAvatar 的方法名,它自身的名字也不能被改为 header1、header2。 '这种耦合性会使程序变得僵硬' ~~~ ~~~ login.succ(function(data){ header.setAvatar( data.avatar); // 设置 header 模块的头像 nav.setAvatar( data.avatar ); // 设置导航模块的头像 message.refresh(); // 刷新消息列表 cart.refresh(); // 刷新购物车列表 }); ~~~ >[danger] ##### 发布订阅模式进行改进 ~~~ 1.用发布—订阅模式重写之后,对用户信息感兴趣的业务模块将自行订阅登录成功的消息事件。 当登录成功时,登录模块只需要发布登录成功的消息,而业务方接受到消息之后,就会开始进行 各自的业务处理,登录模块并不关心业务方究竟要做什么,也不想去了解它们的内部细节 ~~~ * 需要触发通知 ~~~ $.ajax( 'http:// xxx.com?login', function(data){ // 登录成功 login.trigger( 'loginSucc', data); // 发布登录成功的消息 }); ~~~ * 将各个模块的订阅者假如发布者的缓存列表中 ~~~ 1.以后在需要有要在登录模块调用方法的地方你只需要加入自己所需要通知对象 进去即可。 ~~~ ~~~ var header = (function(){ // header 模块 login.listen( 'loginSucc', function( data){ header.setAvatar( data.avatar ); }); return { setAvatar: function( data ){ console.log( '设置 header 模块的头像' ); } } })(); var nav = (function(){ // nav 模块 login.listen( 'loginSucc', function( data ){ nav.setAvatar( data.avatar ); }); return { setAvatar: function( avatar ){ console.log( '设置 nav 模块的头像' ); } } })(); ~~~ >[danger] ##### 总结 ~~~ 1.这里我个人的理解是,你的模板决定了其他模块的方法加载,尝试使用发布订阅模式, 而不是我自己写了一个模块,这个模块中有一个方法加载的时候需要调用你自己这个 模块中的其他方法你来使用'发布订阅模式' ~~~