组合模式(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设计模式一书,让我们一点点积累一点点成长,希望对大家有所帮助。
来源: http://www.cnblogs.com/chen-jie/p/JavaScript-Composite.html