JavaScript 设计模式 :用组合模式写出复杂组件

组合模式

  • 什么是组合模式
  • 生活中的组合模式
  • 组合模式的实际运用
  • 为何使用js继承

js继承文献javascript

官方: 组合模式,将对象组合成树形结构以表示“部分-总体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具备一致性。掌握组合模式的重点是要理解清楚 “部分/总体” 还有 ”单个对象“ 与 "组合对象" 的含义。css

  • 好了,你能够忽略我上面说的废话,下面听我BB。

传说中的23中设计模式的命名者已经告诉你们这大概是一个什么样的套路,但咱们之后要讨论的不只仅要了解,还能够找机会使用。html

生活中的组合模式

生活中仍是有不少的组合模式的:麦当劳套餐饭店美团X人套餐联通流量包等等,他们把多个‘个体’组合成了一个‘总体’,这是生活中的例子,让我用最近的实际小项目来讲话。java

举个栗子:

最近在公司有一个小模块叫‘甘特图’,github基本都是这样的: jquery

可是公司怎能要这种传统的东西呢,必需要创新!!!具体有啥呢,传统只有一条线,老板:给我加两条,一条预期,一条实际,要有mileStone(里程碑),加个总进度,加个....云云,信心满满的你是否被吓到了呢,我我的实现了一份,不过可能使用组合模式会更好,咱们下面简单尝试一下使用组合模式吧 😆。git

首先,咱们肯定咱们作一个组件名字就叫Gantt(肯德基)吧,组件包括什么呢:分为这几个小组件(套餐):画图套餐(包括:进度条,背景网格,内容补充),格式化套餐,加上一些简单的工具类:得到最长时间,日期格式化,只是给你们举个栗子。github

作好以后大概这个样子 : 编程

github开源地址

这里作一下规范,下文中,我将把Gantt叫作(商店)小组件叫作(套餐),组件内原型方法叫作(成员)。设计模式

  • 先造一个继承器轮子↓
//创建一个属于咱们本身的Jquery,里面只有inheritObject、inheritPrototype两个方法,
    (function () {
    var util = {
        inheritObject: function (o) {//对象继承封装
            var F = function () {
            };
            F.prototype = o;
            return new F();
        },
        inheritPrototype: function (subclass, supperclass) {//原型继承封装
            var obj = this.inheritObject(supperclass.prototype);
            obj.constructor = subclass;
            subclass.prototype = obj;
        }
    };
    window.$ = window.util = util;
})(window);//把闭包变量弄到全局

var Gantt = function (data) {
    this.ganttData = data;
    this.children = [];
    this.element = null;
}

Gantt.prototype = {
    init: function () {
        throw new Error('此方法必须子类重写')
    },
    build: function () {
        throw new Error('此方法必须子类重写')
    },

}

/**
 * 建立 Gantt外层容器
 * @param name
 * @param parent
 * @constructor
 */
var Container = function (name, parent) {
    Gantt.call(this);
    this.name = name;
    this.parent = parent;
    this.init();//构建子容器的基本点(id,dom,name)
}
$.inheritPrototype(Container, Gantt); //


Container.prototype = {
    /**
     *重写父类init
     */
    init: function () {
        this.element = document.createElement('div');//建立一个div元素
        this.element.name = this.name;
        this.element.id = 'ganttView';
        this.parent.append(this.element);
    },
    /**
     *重写父类build
     */
    build: function (child, text) {
        child.append(document.createTextNode(text)); //添加测试描述
        this.children.push(child);
        this.element.appendChild(child);
        return this;
    },
    getElement: function () {
        return this.element;
    },
    draw: function () {
        this.parent.appendChild(this.element)
    }
}
//调用方法
var ganttView = new Container('GanttView', document.body);
ganttView.build(document.createElement("div"), '左侧详情项目1')
    .build(document.createElement("div"), '左侧详情项目2').build(document.createElement("div"), '右侧画图')
      
   
    ```
    
  
节约时间css就不写了,
复制代码
float:left;
height,width,
color,backbround,
text:center.....脑补中...
```
复制代码

那么咱们注意,Container是个次级容器,是根据一个parent也就是最原始的'body'元素逐渐逐渐向里面画的,里面还有更加复杂的内容(计算最大时间范围,画背景,添加日历等等)bash

下面还应该有item里面增长描述详情画图等 固然描述,详情,画图都只是‘套餐’,仍是须要最底层的‘成员’来作地基的,成员是最基层的,他再也不拥有子类,可是他们继承了父类。

那么咱们总体修改一下代码:

var Gantt = function (data) {
        this.ganttData = data;
        this.children = [];
        this.element = null;
    }

    Gantt.prototype = {
        init: function () {
            throw new Error('此方法必须子类重写')
        },
        build: function () {
            throw new Error('此方法必须子类重写')
        },

    }

    /**
     * 建立 Gantt外层容器
     * @param name
     * @param parent
     * @constructor
     */
    var Container = function (name, parent) {
        Gantt.call(this);
        this.name = name;
        this.parent = parent;
        this.init();//构建子容器的基本点(id,dom,name)
    }
    $.inheritPrototype(Container, Gantt); //


    Container.prototype = {
        /**
         *重写父类init
         */
        init: function () {
            this.element = document.createElement('div');//建立一个div元素
            this.element.id = 'ganttView';
            this.element.textContent= this.name;
            this.parent.append(this.element);
        },
        /**
         *重写父类build
         */
        build: function (child) {
//            child.append(document.createTextNode(text)); //添加测试描述
            this.children.push(child);
            this.element.appendChild(child.element);
            return this;
        },
        getElement: function () {
            return this.element;
        },
        draw: function () {
            this.parent.appendChild(this.element)
        }
    }

    /**
     * 建立 Gantt基础成员
     * @param name
     * @param parent
     * @constructor
     */
    var Item = function (name, parent) {
        Gantt.call(this);
        this.name = name;
        this.parent = parent;
        this.init();//构建子容器的基本点(id,dom,name)
    }
    $.inheritPrototype(Item, Container); //

    Item.prototype = {
        /**
         *重写父类init
         */
        init: function () {
            this.element = document.createElement('div');//建立一个div元素
            this.element.id = 'ganttItem';
            this.element.textContent = this.name;
//            this.parent.append(this.element);
//            return this.element;
        },
        /**
         *重写父类build
         */
        build: function (text) {
            //能够再画进度条,以及为进度条绑定点击事件
        },
        getElement: function () {
            return this.element;
        },
        draw: function () {
            this.parent.appendChild(this.element)
        }
    }

    //调用方法
    var container = new Container('GanttView', document.body);
        container.build(new Item('左侧详情项目1'))
                .build(new Item('左侧详情项目2'))
                
                ```
 
 ![](https://user-gold-cdn.xitu.io/2017/10/18/997cfd2b701a539045c4dad52aa460f3)
    
- 为何要使用`继承`,贼麻烦.我直接`new`不行么?

 “行,可是记住一点,咱们使用了组合模式就要保障接口的统一,这也是[面向对象编程](https://juejin.im/post/58ff6374570c350058f489b5)的思想,相似`java`的`interface`接口,这样咱们处理回调、异常更加方便,简化了复杂的总体,又经过子类丰富了总体。“
    
我原来写的甘特图,是一次性生成的,若是产品提出,若使用`长轮循`监听到服务器,若是服务器增长了一个任务,以动画的形式动态添加一条进度条,这对于我之前的组件来讲改动比较大,可是这个就很简单了,可能咱们加一个add原型方法继承就行了。
    
- 那么组合模式有啥好处?
    “使得项目更加模块化,一个组件能够无限向下分红各个套餐,直到到达最底层的成员,以原子粒度书写代码,对于代码维护十分有利。”
    
    
开源的[Gantt插件](https://github.com/pkwenda/gantt.js)是基于`Jquery`的扩展插件,没有用到svg等笨重的组件,只依赖jquery,只有14k,还有一些亮点没有提交,当时写的比较匆忙,如今最近想一想也许当时考虑用组合模式更加适合于之后需求的变动。极大节约开发时间。
    
### 最后但愿你们能写出更加风骚的代码
 
复制代码
相关文章
相关标签/搜索