组合模式

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

如果有一个需求需要我们做一个门户网站,涉及到门户网站自然离不开文章列表,那么文章列表里又有文字列表,图片列表,图文列表,这么多种类的文章列表我们该怎么做呢?

首先我们可以创建一个文章列表的抽象父类,让其他的不同类型的文章列表都继承于这个类

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

我们定义了这个接口抽象父类,下一步我们就是要实现所有的子类,但是我们要注意他们的层次关系,因为组合模式不仅仅是单层次组合,也可以是一个多层次的。

接着我们定义一个文章列表模块容器类

var Container=function(id,parent){
//构造函数继承父类
articles.call(this);
//模块ID
this.id=id;
//模块的父容器
this.parent=parent;
//构建初始化方法
this.init();
}

原型式继承

function proObject(o){
//声明一个过渡函数对象
function Obj(){}
//过渡对象的原型继承父对象
Obj.prototype=o;
//返回过渡对象的一个实例,该实例的原型继承了父对象
return new Obj();
}

寄生式组合式继承父类原型方法

function parasiticType(ParentClass,ChildClass){
//复制一份父类的原型保存在变量中
var parent=proObject(ParentClass.prototype);
//修正因为重写子类原型导致子类的constructor属性被修改
parent.constructor=ChildClass;
//设置子类的原型
ChildClass.prototype=parent;
} parasiticType(articles,Container);

接着我们实现之前的初始化方法

Container.prototype.init=function(){
this.element=document.createElement('ul');
this.element.id=this.id;
this.element.className='articles-container'
}

现在我们实现抽象父类中的方法

Container.prototype.add=function(child){
console.log(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);
}

同样的下一层级的行成员集合类实现方法与之类似。

var Item=function(className){
articles.call(this);
this.className=className||"";
this.init();
}
parasiticType(articles,Item);
Item.prototype.init=function(){
this.element=document.createElement('li');
this.element.className=this.className;
}
Item.prototype.add=function(child){
console.log(child);
//在子元素容器中插入子元素
this.children.push(child);
//插入当前组件元素树中
this.element.appendChild(child.getElement());
return this;
}
Item.prototype.getElement=function(){
return this.element;
}

文章组合实体类实现方法也是一样的

var articlesGroup=function(className){
articles.call(this);
this.className=className||"";
this.init();
}
parasiticType(articles,articlesGroup);
articlesGroup.prototype.init=function(){
this.element=document.createElement('div');
this.element.className=this.className;
}
articlesGroup.prototype.add=function(child){
//在子元素容器中插入子元素
this.children.push(child);
//插入当前组件元素树中
this.element.appendChild(child.getElement());
return this;
}
articlesGroup.prototype.getElement=function(){
return this.element;
}

好了现在我们已经把所有子类成员创建出来了,不过光有这些容器类还不行,还需要有更底层的文章列表类。

图片文章列表

var ImageArticles=function(url,href,className){
articles.call(this);
this.url=url||"";
this.href=href||"#";
this.className=className||"normal";
this.init();
}
parasiticType(articles,ImageArticles);
ImageArticles.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;
}
ImageArticles.prototype.add=function(){}
ImageArticles.prototype.getElement=function(){
return this.element;
}

文字文章列表

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

现在所有的类我们都已经创建了,现在我们就要通过add方法来组合这些类

var Articles=new Container('articles',document.body);
Articles.add(new Item('normal').add(
new ImageArticles('img/HBuilder.png','#','small')
)
.add(new Item('normal').add(
new ImageArticles('img/HBuilder.png','#','small')
)
)
.add(new Item('normal').add(
new TextArticles('测试列表','#')
)
)
.add(new Item('normal').add(
new TextArticles('测试列表2','#')
)
)
).show();

我们来看一看效果,这里我就偷懒不写样式了。我们可以看到,列表已经颇具雏形了。

现在我们创建的每一条文章列表都是一个独立的个体,互不影响,避免相互间的耦合,也增强了组合后的模块的复杂性,如果需要混搭,我们做出相应的组合就可以轻易的完成

总结

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

也谢谢大家看到这里:)如果你觉得我的分享还可以请点击推荐,分享给你的朋友让我们一起进步~

好了以上就是本次分享的全部内容,本次示例参考自JavaScript设计模式一书,让我们一点点积累一点点成长,希望对大家有所帮助。

欢迎转载,转载请注明作者,原文出处。

再起航,我的学习笔记之JavaScript设计模式15(组合模式)的更多相关文章

  1. 再起航,我的学习笔记之JavaScript设计模式08(建造者模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前几 ...

  2. 再起航,我的学习笔记之JavaScript设计模式09(原型模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 我们 ...

  3. 再起航,我的学习笔记之JavaScript设计模式11(外观模式)

    经过一段时间的学习与分享,我们对创建型设计模式已经有了一定的认识,未来的一段时间里我们将展开新的篇章,开始迈入结构性设计模式的学习. 结构性设计模式与创建型设计模式不同,结构性设计模式更偏向于关注如何 ...

  4. 再起航,我的学习笔记之JavaScript设计模式14(桥接模式)

    桥接模式 桥接模式(Bridge): 在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦 从定义上看桥接模式的定义十分难以理解,那么我们来通过示例来演示什么是桥接模式. 现在我们需要做一个导航 ...

  5. 再起航,我的学习笔记之JavaScript设计模式17(模板方法模式)

    模板方法模式 由模板方法模式开始我们正式告别结构型设计模式,开始行为型设计模式的学习分享 行为型设计模式用于不同对象之间职责划分或算法抽象,行为型设计模式不仅仅涉及类和对象,还涉及类或对象之间的交流模 ...

  6. 再起航,我的学习笔记之JavaScript设计模式20(策略模式)

    策略模式 策略模式(Strategy):将定义的一组算法封装起来,使其相互之间可以替换.封装的算法具有一定的独立性,不会随客户端变化而变化. 其实策略模式在我们生活中可应用的地方还是比较多的,比如在商 ...

  7. 再起航,我的学习笔记之JavaScript设计模式22(访问者模式)

    访问者模式 概念介绍 访问者模式(Visitor): 针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法 解决低版本IE兼容性 我们来看下面这段代码,这段代码,我们封装了一个绑定 ...

  8. 再起航,我的学习笔记之JavaScript设计模式24(备忘录模式)

    备忘录模式 概念介绍 备忘录模式(Memento): 在不破坏对象的封装性的前提下,在对象之外捕获并保存该对象内部的状态以便日后对象使用或者对象恢复到以前的某个状态. 简易分页 在一般情况下我们需要做 ...

  9. 再起航,我的学习笔记之JavaScript设计模式25(迭代器模式)

    迭代器模式 概念介绍 迭代器模式(Iterator): 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素. 迭代器 程序中的循环是一种利器,循环语句也使我们程序开发更简洁高效,但是有时一遍 ...

随机推荐

  1. laravel 事件监听

    事件监听器监听到事件发生后会执行一些操作,Laravel使用观察者模式来实现这种监听机制 操作顺序:1.注册事件和监听器 -> 2.定义事件类 -> 3.定义监听类 -> 4.触发事 ...

  2. 构建高并发&高可用&安全的IT系统-高并发部分

    什么是高并发? 狭义来讲就是你的网站/软件同一时间能承受的用户数量有多少 相关指标有 并发数:对网站/软件同时发起的请求数,一般也可代表实际的用户 每秒响应时间:常指一次请求到系统正确响的时间(以秒为 ...

  3. (转)Synchronized(对象锁)和Static Synchronized(类锁)的区别

    场景:面试的时候经常用得到! 1 综述 Synchronized和Static Synchronized区别 一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念),一个是全 ...

  4. 1分钟选好最合适你的JavaScript框架

    欢迎大家持续关注葡萄城控件技术团队博客,更多更好的原创文章尽在这里~~​ Javascript框架(以下简称框架)也被称为Javascript库,是一组包含丰富功能和函数的JavaScript代码集, ...

  5. AtCoder Beginner Contest 068

    A - ABCxxx 题意: 给出n,输出“ABCn”就可以了,纯水题. B - Break Number 题意: 给出n,找出从1到n的闭区间内能够被2整除最多次的数. 思路: 直接模拟. 代码: ...

  6. 使用Node.js调用阿里云短信的发送以及接收

    为了使用Node.js调用阿里云短信服务,我自己写了个npm包, 目前实现了: 使用Node.js调用阿里云短信服务,发送短信: 使用Node.js调用阿里云短信服务以及MNS服务,接收用户上行短信 ...

  7. JavaScript获取客户端IP地址

    1. 第三方接口 1) 这里提供一个搜狐接口的地址:http://pv.sohu.com/cityjson?ie=utf-8 ,将这个js引入到页面即可得到returnCitySN. 2) api.i ...

  8. ddos攻击和cc攻击的区别和防护!!

    什么是DDoS攻击? DDoS攻击就是分布式的拒绝服务攻击,DDoS攻击手段是在传统的DoS攻击基础之上产生的一类攻击方式.单一的DoS攻击一般是采用一对一方式的,随着计算机与网络技术的发展,DoS攻 ...

  9. RabbitMQ安装以及java使用(一)

    最近闲来无事,整理下基础知识,本次安装 1.RabbitMQ版本是3.6.10 2.操作系统是centOS 7 64位  虚拟机IP:192.168.149.133 1.安装更新系统环境依赖 yum ...

  10. 学问Chat UI(1)

    前言 由于项目需要,最近开始借鉴学习下开源的Android即时通信聊天UI框架,为此结合市面上加上本项目需求列了ChatUI要实现的基本功能与扩展功能. 融云聊天UI-Android SDK 2.8. ...