记录对一段js代码重构的理解
2016-01-07 00:00
821 查看
功能具备但组织结构比较混乱的代码:
下面是重构后的:
function Product(id, description) { this.getId = function () { return id; }; this.getDescription = function () { return description; }; } function Cart(eventAggregator) { var items = []; this.addItem = function (item) { items.push(item); }; } (function () { var products = [new Product(1, "Star Wars Lego Ship"), new Product(2, "Barbie Doll"), new Product(3, "Remote Control Airplane")], cart = new Cart(); function addToCart() { var productId = $(this).attr('id'); var product = $.grep(products, function (x) { return x.getId() == productId; })[0]; cart.addItem(product); var newItem = $('<li></li>').html(product.getDescription()).attr('id-cart', product.getId()).appendTo("#cart"); } products.forEach(function (product) { var newItem = $('<li></li>').html(product.getDescription()) .attr('id', product.getId()) .dblclick(addToCart) .appendTo("#products"); }); })();
下面是重构后的:
/*这里有两个实体:产品和购物车;产品有自己的集合,同时购物车也可以看成产品的集合;产品和购物车都各自的视图; *单个实体对应的视图上的孤立事件(不会影响到其它实体或对应的视图)不需要用到事件对象,实体之间发生交互时才需要事件对象 *订阅和发布方法的调用对象都是事件集合的实例,这个无关紧要,重要的是它们调用时的位置,与用户有直接交互的视图对应的实体往往是发布者,被联动影响的实体往往是订阅者。 如:用户双击产品,产品会添加到购物车,这里与用户直接交互的是产品,间接被影响的是购物车,每个产品都有同样的双击事件,所以双击事件方法统一写到产品集合中,与实体间交互相关的发布动作紧随其后。产品添加到购物车其实有两个动作:产品实例添加到购物车中缓存、产品出现在购物车视图上。在产品上双击实际上只是直接产生了前一个动作,后一个动作被间接触发了 */ /*事件对象 *内容:事件名称、事件回调集合、添加/删除/触发事件回调 *事件对象一定有事件名称,不一定有事件回调,创建事件对象时一定要指定事件名称 */ function Event(name){ var handlers = []; this.getName = function(){ return name; }; this.addHandler = function (handler){ handlers.push(handler); }; this.removeHandler = function(handler){ for(var l=handlers.length;l--;){ if(handler == handlers[l]){ handlers.splice(l+1,1); break; } } }; this.fire = function(eventArgs){ handlers.forEach(function(h){ h(eventArgs); }); } } /*事件集合 *功能:缓存事件对象,从缓存中获取指定名称的事件对象(提供集合的缓存元素功能) *往集合中添加指定事件、触发指定事件(对集合中元素的操作能力) * */ function EventAggregator(){ var events = []; function getEvent(eventName){ return $.grep(events, function(event){ return event.getName() === eventName; })[0]; } this.publish = function (eventName, eventArgs){ var event = getEvent(eventName); if(!event){ event = new Event(eventName); events.push(event); } event.fire(eventArgs); } this.subscribe = function(eventName, handler){ var event = getEvent(eventName); if(!event){ event = new Event(eventName); events.push(event); } event.addHandler(handler); } } /*第二个实体:购物车 *购物车是产品的一个集合 *有添加产品方法,必然会导致一个添加产品事件在这里发布 *可能还有删除产品方法 *只是提供接口,表示它有这些能力,到控制器中去使用这些能力 */ function Cart(eventAggregator){ var items = []; this.addItem = function(item){ items.push(item); eventAggregator.publish('itemAdded', item);/*把它写在这而不是控制器中的原因是:可能有多种方式添加产品到购物车,写在这避免了在控制器里的每一种添加产品方式后都加上这么一句*/ } } /*购物车相关事件的观察者 *各种相关事件的订阅 *把它从Cart类中剥离出来的原因就是这里有视图相关的操作,或者把那些对购物车中产品的操作都集中到这里,来体现控制器的语义 */ function CartController(cart, eventAggregator){ eventAggregator.subscribe('itemAdded', function(eventArgs){ var newItem = $('<li>').html(eventArgs.getDescription()).attr('id-cart',eventArgs.getId()).appendTo('#cart'); }); /*这是个连环事件*/ eventAggregator.subscribe('productSelected', function(eventArgs){ cart.addItem(eventArgs.product); }); } /*第一个实体:产品*/ function Product(id, description){ this.getId = function(){ return id; } this.getDescription = function(){ return description; } } /*产品的另一个集合 *包括导出数据集合的方法 *也包括从后台获取数据、组装成产品对象的方法 *还可能包含删除产品的方法 */ function ProductRepository(){ var products = [new Product(1,'Star wars lego ship'), new Product(2, 'Barbie doll'), new Product(3, 'Remote control airplane')]; this.getProducts = function(){ return products; } } /*产品的观察者 *给每个产品绑定点击事件 *产品发生点击事件添加到购物车后,必然会导致一个购物车添加产品的事件被发布 *结构和购物车的观察者类似,传入的参数也相似 */ function ProductController(productRepository, eventAggregator){ var products = productRepository.getProducts(); function onProductSelected(){ var productId = $(this).attr('id'); var product = $.grep(products, function(x){ return x.getId() == productId; })[0]; eventAggregator.publish('productSelected', {product: product}); } products.forEach(function(product){ var newItem = $('<li>').html(product.getDescription()) .attr('id', product.getId()) .dblclick(onProductSelected) .appendTo($('#products')); }); } (function(){ var eventAggregator = new EventAggregator(), cart = new Cart(eventAggregator), cartController = new CartController(cart, eventAggregator), productRepository = new ProductRepository(), productController = new ProductController(eventAggregator, productRepository); }());
相关文章推荐
- js打印局部页面
- js调试method
- js 中的继承
- JavaScript 正则表达式上——基本语法
- 处理json工具类JacksonUtil
- javascript开发HTML5游戏--斗地主(单机模式part3)
- ExtJS远程数据-本地分页
- JavaScript:理解instanceof
- JavaScript 操作 Cookie
- javascript小白学习指南4--持续更新
- javascript attachEvent addEventListener 监听事件
- bzoj1031【JSOI2007】字符加密Cipher
- JS_ 垃圾回收、变量与属性、作用域链
- JS模块化规范CommonJS,AMD,CMD
- 什么是JS闭包
- JavaScript打字游戏 01
- JavaScript函数惰性载入
- 实现 jstl标签foreach 功能
- js中对字符串的处理
- TypeError: window.clipboardData is undefined