【D1n910】《JavaScript 设计模式》第14章 超值午餐—— 组合模式
正常操作,正常分析,大家好,我是D1n910。
今天继续来学习 《JavaScript 设计模式》的第三篇 结构型设计模式
这是一个连续的读书笔记,所以如果你之前的内容没有看的话,可以去看看。
下面是第十章的展览,里面其实链接好了所有1~10的专栏内容,所以直接戳下面的专栏链接就可以快速到达啦。

其他后续章节


这里再次感谢 《Javascript 设计模式》及其作者 张荣铭,专栏内容是在它的基础上生成的。
现在会觉得很多设计模式离我们有点遥远,是因为我们现在都在用大佬写好的框架吧,很多设计模式都包含在框架里了。

第三篇 结构型设计模式
结构型设计模式关注于如何将类或者对象组合成更大、更复杂的结构,以简化设计。
第 14 章 超值午餐——组合模式
组合模式(Composite):又称部分-整体模式,将对象组合成树形结构以表示“部分整体”的层次结构。
组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式能够给我们提供一个清晰的组成结构。
组合对象通过继承同一个父类使其具有统一的方法。感觉就好像我们的一个个组件。
14.1、新闻模块十万火急(P94)
小新接到了新闻模块的需求。
“新闻模块里要添加一条文字新闻。
“新闻模块里要添加一条带有直播图标的文字新闻。
“新闻模块里要添加一条已分类的文字新闻。
“图片新闻和文字新闻放在一行”
……
很多这样的新闻模块下的需求扔过来了。
希望能够用组合模式的方式,讲这些模块从新闻模块中拆出来,作为一个个个体,各自整理好后组合使用。
14.2、餐厅里的套餐业务(P95)
就好像到餐厅里,我们可以直接点一份份套餐,这些套餐里都是不同的做好的食物组合起来的。
14.3、每个成员要有祖先(P95)
考虑到要做这种组合模式之前,我们要有一个指挥做我们一个个个体类的总类,也就是我们之前学的抽象工厂模式里涉及到的抽象类。
通过这样的一个抽象类来定义我们要创建的新闻类簇。
这个抽象类也相当于是虚拟父类:
var News = function () {
// 子组件容器
this.children = [];
// 当前组件元素
this.element = null;
}
News.prototype = {
init: function () {
throw new Error('请重写你的方法');
},
add: function () {
throw new Error('请重写你的方法');
},
getElement: function () {
throw new Error('请重写你的方法');
}
}
这里定义对象公有树形的原因是因为后面所有继承子类都会声明这两个变量,为了简化子类,我们可以这么做。
14.4、组合要有容器类(P96)
从上面的需求我们可以知道,这次的新闻需求会有三种容器类
新闻容器
行容器
能够包含两种新闻的新闻组合体容器
// 新闻容器
// 容器类构造函数
var NewsContainer = function(id, parent) {
// 构造函数继承父类
News.call(this);
// 模块的 id
this.id = id;
// 模块的父容器
this.parent = parent;
// 构造器
this.init();
}
// 寄生式继承父类原型方法
inheritPrototype(NewsContainer, News);
NewsContainer.prototype.init = function () {
this.element = document.createElement('ul');
this.element.id = this.id;
this.element.className = 'new-container';
};
// 添加子元素的方法
NewsContainer.prototype.add = function (child) {
this.children.push(child);
this.element.appendChild(child.getElement);
return this;
}
// 获取当前元素的方法
NewsContainer.prototype.getElement = function(child) {
return this.element;
}
// 展示子元素
NewsContainer.prototype.show = function () {
this.parent.appendChild(this.element);
}
// 行成员集合类,行容器
// 行容器
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(child) {
return this.element;
}
// 创建新闻组合体容器
// 新闻组合体容器
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;
}
14.5、创建一个新闻类(P97)
完成上面的容器类以后,我们就可以去创建我们的新闻类了。
新闻类就没有子类了,所以也就没有 add 方法,可声明也可不声明。(书中是建议声明一个空函数)
// 图片新闻类
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.getElement = function () {
return this.element
}
// icon新闻类
var IconNews = function (text, url, type) {
News.call(this)
this.url = url || ''
this.text = text || '';
this.type = type || 'dn';
this.init()
}
inheritPrototype(IconNews, News)
IconNews.prototype.init = function () {
this.element = document.createElement('a');
var icon = document.createElement('i');
icon.className = 'iconfont icon-' + this.type;
var text = document.createTextNode(this.text);
this.element.appendChild(icon);
this.element.appendChild(text);
this.element.href = this.href;
this.element.className = 'icon-news';
}
IconNews.prototype.getElement = function () {
return this.element
}
// 创建纯文字新闻类
var EasyNews = function (text, href) {
News.call(this)
this.href = href || ''
this.text = text || '';
this.init()
}
inheritPrototype(EasyNews, News)
EasyNews.prototype.init = function () {
this.element = document.createElement('a');
this.element.innerText = this.text
this.element.href = this.href;
}
EasyNews.prototype.getElement = function () {
return this.element
}
// 带 tag 模块
var TagsNews = function (text, href, type, pos) {
News.call(this)
this.href = href || '';
this.text = text || '';
this.type = type || '';
this.pos = pos || 'left'
this.init()
}
inheritPrototype(TagsNews, News)
TagsNews.prototype.init = function () {
this.element = document.createElement('a');
this.element.href = this.href;
if (this.post === 'left') {
this.element.innerHTML = '[' + this.type + ']' + this.text
} else {
this.element.innerHTML = this.text + '[' + this.type + ']'
}
}
TagsNews.prototype.getElement = function () {
return this.element
}
14.6、把新闻模块创建出来(P99)
通过使用上面的基类,最终使用以后,我们就可以创建出新闻模块啦。


14.7、表单的应用(P100)
现在想一想,可以用上面的组合模式,把下面的表单填写内容解成基类,然后组合起来。

本章 End,学习进度 14/40,加油加油
D1n910 于2021年02月20日 17:19 在南山后海