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

JavaScript 设计模式 :用组合模式写出复杂组件组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。 好了,你可以忽略我上面说的废话,下面听我BB。 传说中的23中设计…

组合模式

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

js继承文献

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

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

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

生活中的组合模式

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

举个栗子:

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

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

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

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

做好之后大概这个样子 :

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

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’元素逐渐逐渐向里面画的,里面还有更加复杂的内容(计算最大时间范围,画背景,添加日历等等)

下面还应该有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://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/10/18/997cfd2b701a539045c4dad52aa460f3~tplv-t2oaga2asx-image.image)
    
- 为什么要使用`继承`,贼麻烦.我直接`new`不行么?

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

今天的文章JavaScript 设计模式 :用组合模式写出复杂组件分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/23362.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注