美文网首页
JavaScript设计模式 | 14-组合模式

JavaScript设计模式 | 14-组合模式

作者: 夏海峰 | 来源:发表于2019-02-21 22:10 被阅读1次

1、模式定义

组合模式,又称“部分-整体”模式,把对象组合成树形结构,以表示出“部分-整体”的层次结构。组合模式,使得用户对单个对象和组合对象的使用具有一致性。

2、生活中的组合模式

餐饮店里的套餐,是由几个独立的部分组合而成。所谓的组合模式,就把一个“整体”分割成若干个相互独立的“部分”。这样的做法,不仅可以简化“整体”的复杂性,还可以通过拓展“部分”来增强整体的丰富性。

组合模式,不仅仅是单层次组合,还可以进行多层次的组合。所谓的多层次组合,就是把“部分”看成“小的整体”,继续向下拆分出更多更小的“部分”,依次类推。

3、组合模式 举例

现在我们以新闻版块作为需求来举例。在新闻版块中,有的新闻列表有图片,有的新闻列表还有直播图标,有的新闻列表只有文字,等等。在这种情景下,我们就可以把新闻列表看成一个“整体”,把其中的图片、图标、文字等看成“部分”。最后通过组合模式,即可实现多种不同结构的新闻列表。

1)新闻基类:定义一个统一的顶级的接口父类。让所有的与新闻相关的类都继承自这个接口父类。在接口父类中,定义出必须的成员变量和方法。

var News = function() {
    // 子组件容器
    this.children = {};
    // 当前组件元素
    this.element = {};
}
News.prototype = {
    init: function() {
        throw new Error("请重写 init 方法");
    },
    add: function() {
        throw new Error("请重写 add 方法");
    },
    getElement: function() {
        throw new Error("请重写 getElement方法");
    }
}

2)创建一个容器类,用于包裹所有新闻列表,代表一个新闻版块。

// 定义一个容器类
var Container = function(id, parent) {
    News.call(this);
    this.id = id;
    this.parent = parent;
    this.init();
}
// 寄生式继承:让Container类继承自 News接口类
inheritPrototype(Container, News);

Container.prototype.init = function() {
    this.element = document.createElement("ul");
    this.element.id = this.id;
    this.element.className = "new-container";
}
Container.prototype.add = function(child) {
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
}
Container.prototype.getElement = function() {
    return this.element;
}
Container.prototype.show = function() {
    this.parent.appendChild(this.element);
}

3)新闻列表类,代表新闻模块中的一条新闻。

var Item = function(classname) {
    News.call(this);
    this.classname = classname || "";
    this.init();
}
inheritPrototype(Item, News);
Item.prototype.init = function() {
    this.element = document.createElement("li");
    this.element.className = this.classname;
}
Item.prototype.add = function(child) {
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
}
Item.prototype.getElement = function() {
    return this.element;
}

4)用于把多条新闻列表构成一个“组”,即对多条新闻列表进行分组。

var NewsGroup = function(classname) {
    News.call(this);
    this.classname = classname || '';
    this.init();
}
inheritPrototype(NewsGroup, News);
NewsGroup.prototype.init = function() {
    this.element = document.createElement('div');
    this.element.className = this.classname;
}
NewsGroup.prototype.add = function(child) {
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
}
NewsGroup.prototype.getElement = function() {
    return this.element;
}

5)第一种类型的新闻列表:带有图片的新闻列表类。

var ImageNews = function(url, href, classname) {
    News.call(this);
    this.url = url || "";
    this.href = href || "#";
    this.classname = classname || "normal";
    this.init();
}
inheritPrototype(ImageNews, News);
ImageNews.prototype.init = function() {
    this.element = document.createElement("a");
    var img = new Image();
    img.src = this.url;
    this.element.appendChild(img);
    this.element.className = 'image-news ' + this.classname;
    this.element.href = this.href;
}
ImageNews.prototype.add = function() {};
ImageNews.prototype.getElement = function() {
    return this.element;
}

6)第二种类型的新闻列表:带有 ICON 图标的新闻列表类。

var IconNews = function(text, href, type) {
    News.call(this);
    this.text = text || "";
    this.href = href || "#";
    this.type = type || "video";
    this.init();
}
inheritPrototype(IconNews, News);
IconNews.prototype.init = function() {
    this.element = document.createElement("a");
    this.element.innerHTML = this.text;
    this.element.href = this.href;
    this.element.className = 'icon ' + this.type;
}
IconNews.prototype.add = function() {};
IconNews.prototype.getElement = function() {
    return this.element;
}

7)第三种类型的新闻列表:普通的只有文字的新闻列表类。

var EasyNews = function(text, href) {
    News.call(this);
    this.text = text || "";
    this.href = href || "#";
    this.init();
}
inheritPrototype(EasyNews, News);
EasyNews.prototype.init = function() {
    this.element = document.createElement("a");
    this.element.innerHTML = this.text;
    this.element.href = this.href;
    this.element.className = "text";
}
EasyNews.prototype.add = function() {}
EasyNews.prototype.getElement = function() {
    return this.element;
}

8)第四种类型的新闻列表:带有类别标识的新闻列表类。

var TypeNews = function(text, href, type, pos) {
    News.call(this);
    this.text = text || "";
    this.href = href || "#";
    this.type = type || "";
    this.pos = pos || "left";
    this.init();
}
inheritPrototype(EasyNews, News);
TypeNews.prototype.init = function() {
    this.element = document.createElement("a");
    if (this.pos == "left") {
        this.element.innerHTML = "["+ this.type +"]" + this.text;
    } else {
        this.element.innerHTML = this.text + "["+ this.type +"]";
    }
    this.element.href = this.href;
    this.element.className = "text";
}
TypeNews.prototype.add = function() {}
TypeNews.prototype.getElement = function() {
    return this.element;
}

9)使用上述所封装的各个“局部”组件创建一个“整体”的完整的新闻版块。

var newsBlock = new Container("news", document.body);

newsBlock.add(
    new Item("normal").add(
        new IconNews("梅西不拿金球也伟大", "#", "video")
    )
).add(
    new Item("normal").add(
        new IconNews("保护强国强队用意明显", "#", "live")
    )
).add(
    new Item("normal").add(
        new NewsGroup("has-img").add(
            new ImageNews("./img/1.png", "#", "small")
        ).add(
            new EasyNews("从240斤胖子成功变型男", "#")
        ).add(
            new EasyNews("五大雷人跑步机", "#")
        )
    )
).add(
    new Item("normal").add(
        new TypeNews("AK47不愿为费城打球", "#", "NBA", "left")
    )
).add(
    new Item("normal").add(
        new TypeNews("火炮飚6三分创新高", "#", "CBA", "right")
    )
).show();
图例

4、组合模式 再举例

组合模式在表单应用中非常有用,把表单元素作为基本的“部分”,可以组合成多种不同结构的“整体”表单。伪代码如下:

var oForm = new FormItem('form-item', document.body);

oForm.add(
    new FieldsetItem('account', '账号').add(
        new Group().add(
            new LabelItem('user-name', '用户名:')
        ).add(
            new InputItem('user-name')
        ).add(
            new SpanItem('4到6位数字或字母')
        )
    ).add(
        new Group().add(
            new LabelItem('user-password', '密码:')
        ).add(
            new InputItem('user-password')
        ).add(
            new SpanItem('6位12位数字或者密码')
        )
    )
).add(
    // ...
).show();
图例

5、小结

组合模式能够给我们提供一个清晰的组成结构。组合对象类通过继承同一个父类使其具有统一的方法,这样也方便了我们统一管理与使用,当然此时单体成员与组合体成员的行为表现就比较一致了。这也就模糊了简单对象与组合对象的区别。有时,这也是一种数据的分级式处理,清晰而又方便地帮助我们管理和使用数据。

当然,组合模式有时在实现需求上给我们带来更多的选择方式,虽然对于单体对象的实现简单而又单一,但是通过对其组合将会给我们带来更多的使用形式。


本章完!!

相关文章

  • JavaScript设计模式 | 14-组合模式

    1、模式定义 组合模式,又称“部分-整体”模式,把对象组合成树形结构,以表示出“部分-整体”的层次结构。组合模式,...

  • 组合模式

    设计模式系列7--组合模式 《Objective-c 编程之道 iOS 设计模式解析》 - 组合模式 常见组合模式...

  • JavaScript设计模式八(组合模式)

    我们先回顾下上一节中的宏命令。 其中marcoCommand被称为组合对象,closeDoorCommand、op...

  • JavaScript 设计模式之组合模式

    引 我们知道地球和一些其他行星围绕着太阳旋转,也知道在一个原子中,有许多电子围绕着原子核旋转。我曾经想象,我们的太...

  • JavaScript 设计模式(八):组合模式

    组合模式:又叫 “部分整体” 模式,将对象组合成树形结构,以表示 “部分-整体” 的层次结构。通过对象的多态性表现...

  • JavaScript设计模式之组合模式

    我们知道地球和一些其他行星围绕着太阳旋转,也知道在一个原子中,有许多电子围绕着原子核旋转。我曾经想象,我们的太阳系...

  • JavaScript进阶:设计模式——组合模式

    1、应用场景 在编写新闻模块时,我们通常会创建图片+文字的一条新闻,或者是icon图标+文字的新闻,也有可能是单纯...

  • 组合模式设计

    一、设计模式 javascript里面给我们提供了很多种设计模式: 工厂、桥、组合、门面、适配器、装饰者、享元、代...

  • 装饰者模式设计

    一、设计模式 javascript里面给我们提供了很多种设计模式: 工厂、桥、组合、门面、适配器、装饰者、享元、代...

  • 适配器模式

    一、设计模式 javascript里面给我们提供了很多种设计模式: 工厂、桥、组合、门面、适配器、装饰者、享元、代...

网友评论

      本文标题:JavaScript设计模式 | 14-组合模式

      本文链接:https://www.haomeiwen.com/subject/dryxyqtx.html