组合模式可以理解为树状结构, 因此组合模式适合对大批对象的操作, 特别是层次结构分明的, 下面我们就来看看号称面向对象的 JavaScript 设计模式开发中组合模式的使用教程
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
我们平时开发过程中,一定会遇到这种情况:同时处理简单对象和由简单对象组成的复杂对象,这些简单对象和复杂对象会组合成树形结构,在客户端对其处理的时候要保持一致性。比如电商网站中的产品订单,每一张产品订单可能有多个子订单组合,比如操作系统的文件夹,每个文件夹有多个子文件夹或文件,我们作为用户对其进行复制,删除等操作时,不管是文件夹还是文件,对我们操作者来说是一样的。在这种场景下,就非常适合使用组合模式来实现。
基本知识
组合模式:将对象组合成树形结构以表示 "部分 - 整体" 的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式主要有三个角色:
(1)抽象组件(Component):抽象类,主要定义了参与组合的对象的公共接口
(2)子对象(Leaf):组成组合对象的最基本对象
(3)组合对象(Composite):由子对象组合起来的复杂对象
理解组合模式的关键是要理解组合模式对单个对象和组合对象使用的一致性,我们接下来说说组合模式的实现加深理解。
组合模式算是为在页面动态创建 UI 量身定做的, 你可以只使用一条命 = 命令为许多对象初始化一些复杂的或者递归的操作. 组合模式提供了两个有点:
(1)允许你将一组对象当成特定的对象. 组合对象 (A composite) 和组成它的子对象实现相同的操作. 对组合对象执行某一个操作将会使该对象下的所有子对象执行相同的操作. 因此你不仅可以无缝的替换单个对象为一组对象集合, 反过来也一样. 这些独立的对象之间即所谓松散耦合的.
(2)组合模式会将子对象集组合成树结构并且允许遍历整个树. 这样可以隐藏内部实现并且允许你以任意的方式组织子对象. 这个对象 (组合对象) 的任何代码将不会依赖内部子对象的实现.
组合模式的实现
(1)最简单的组合模式
html 文档的 DOM 结构就是天生的树形结构,最基本的元素醉成 DOM 树,最终形成 DOM 文档,非常适用适用组合模式。
我们常用的 jQuery 类库,其中组合模式的应用更是频繁,例如经常有下列代码实现:
- $(".test").addClass("noTest").remove("test");
这句简单的代码就是获取 class 包含 test 的元素,然后进行 addClass 和 removeClass 处理,其中不论 $(".test") 是一个元素,还是多个元素,最终都是通过统一的 addClass 和 removeClass 接口进行调用。
我们简单模拟一下 addClass 的实现:
- var addClass = function (eles, className) {
- if (eles instanceof NodeList) {
- for (var i = 0, length = eles.length; i < length; i++) {
- eles[i].nodeType === 1 && (eles[i].className += (' ' + className + ' '));
- }
- }
- else if (eles instanceof Node) {
- eles.nodeType === 1 && (eles.className += (' ' + className + ' '));
- }
- else {
- throw "eles is not a html node";
- }
- }
- addClass(document.getElementById("div3"), "test");
- addClass(document.querySelectorAll(".div"), "test");
这段代码简单的模拟了 addClass 的实现(暂不考虑兼容性和通用性),很简单地先判断节点类型,然后根据不同类型添加 className。对于 NodeList 或者是 Node 来说,客户端调用都是同样的使用了 addClass 这个接口,这个就是组合模式的最基本的思想,使部分和整体的使用具有一致性。
(2)典型的例子
前面我们提到一个典型的例子:产品订单包含多个产品子订单,多个产品子订单组成一个复杂的产品订单。由于 Javascript 语言的特性,我们将组合模式的三个角色简化成 2 个角色:
(1)子对象:在这个例子中,子对象就是产品子订单
(2)组合对象:这里就是产品的总订单
假设我们开发一个旅游产品网站,其中包含机票和酒店两种子产品,我们定义了子对象如下:
- function FlightOrder() { }
- FlightOrder.prototyp.create = function () {
- console.log("flight order created");
- }
- function HotelOrder() { }
- HotelOrder.prototype.create = function () {
- console.log("hotel order created");
- }
上面的代码定义了两个类:机票订单类和酒店订单类,每个类都有各自的订单创建方法。
接下来我们创建一个总订单类:
- function TotalOrders() {
- this.orderList = [];
- }
- TotalOrders.prototype.addOrder = function (order) {
- this.orderList.push(order);
- }
- TotalOrders.prototype.create = function (order) {
- for (var i = 0, length = this.orderList.length; i < length; i++) {
- this.orderList[i].create();
- }
- }
这个对象主要有 3 个成员:订单列表,添加订单的方法,创建订单的方法。
在客户端使用的时候如下:
- var flight = new FlightOrder();
- flight.create();
- var orders = new TotalOrders();
- orders.addOrder(new FlightOrder());
- orders.addOrder(new HotelOrder());
- orders.create();
客户端调用展示了两种方式,一种是单一的创建机票订单,一种是创建多张订单,但最终都是通过 create 方法进行创建,这就是一个很典型的组合模式的应用场景。
来源: http://www.phperz.com/article/17/0224/265677.html