【D1n910】《JavaScript 設(shè)計模式》第14章 超值午餐—— 組合模式
正常操作,正常分析,大家好,我是D1n910。
今天繼續(xù)來學(xué)習(xí) 《JavaScript 設(shè)計模式》的第三篇 結(jié)構(gòu)型設(shè)計模式
這是一個連續(xù)的讀書筆記,所以如果你之前的內(nèi)容沒有看的話,可以去看看。
下面是第十章的展覽,里面其實鏈接好了所有1~10的專欄內(nèi)容,所以直接戳下面的專欄鏈接就可以快速到達(dá)啦。

其他后續(xù)章節(jié)


這里再次感謝 《Javascript 設(shè)計模式》及其作者 張榮銘,專欄內(nèi)容是在它的基礎(chǔ)上生成的。
現(xiàn)在會覺得很多設(shè)計模式離我們有點遙遠(yuǎn),是因為我們現(xiàn)在都在用大佬寫好的框架吧,很多設(shè)計模式都包含在框架里了。

第三篇 結(jié)構(gòu)型設(shè)計模式
結(jié)構(gòu)型設(shè)計模式關(guān)注于如何將類或者對象組合成更大、更復(fù)雜的結(jié)構(gòu),以簡化設(shè)計。
第 14?章 超值午餐——組合模式
組合模式(Composite):又稱部分-整體模式,將對象組合成樹形結(jié)構(gòu)以表示“部分整體”的層次結(jié)構(gòu)。
組合模式使得用戶對單個對象和組合對象的使用具有一致性。
組合模式能夠給我們提供一個清晰的組成結(jié)構(gòu)。
組合對象通過繼承同一個父類使其具有統(tǒng)一的方法。感覺就好像我們的一個個組件。
14.1、新聞模塊十萬火急(P94)
小新接到了新聞模塊的需求。
“新聞模塊里要添加一條文字新聞。
“新聞模塊里要添加一條帶有直播圖標(biāo)的文字新聞。
“新聞模塊里要添加一條已分類的文字新聞。
“圖片新聞和文字新聞放在一行”
……
很多這樣的新聞模塊下的需求扔過來了。
希望能夠用組合模式的方式,講這些模塊從新聞模塊中拆出來,作為一個個個體,各自整理好后組合使用。
14.2、餐廳里的套餐業(yè)務(wù)(P95)
就好像到餐廳里,我們可以直接點一份份套餐,這些套餐里都是不同的做好的食物組合起來的。
14.3、每個成員要有祖先(P95)
考慮到要做這種組合模式之前,我們要有一個指揮做我們一個個個體類的總類,也就是我們之前學(xué)的抽象工廠模式里涉及到的抽象類。
通過這樣的一個抽象類來定義我們要創(chuàng)建的新聞類簇。
這個抽象類也相當(dāng)于是虛擬父類:
var News = function () {
? ?// 子組件容器
? ? this.children = [];
? ? // 當(dāng)前組件元素
? ? this.element = null;
}
News.prototype = {
init: function () {
? ? ? ?throw new Error('請重寫你的方法');
? ?},
add: function () {
? ? ? ?throw new Error('請重寫你的方法');
? ?},
getElement: function () {
? ? ? ?throw new Error('請重寫你的方法');
? ?}
}
這里定義對象公有樹形的原因是因為后面所有繼承子類都會聲明這兩個變量,為了簡化子類,我們可以這么做。
14.4、組合要有容器類(P96)
從上面的需求我們可以知道,這次的新聞需求會有三種容器類
新聞容器
行容器
能夠包含兩種新聞的新聞組合體容器
// 新聞容器
// 容器類構(gòu)造函數(shù)
var NewsContainer = function(id, parent) {
? ?// 構(gòu)造函數(shù)繼承父類
? ?News.call(this);
? ?// 模塊的 id
? ?this.id = id;
? ?// 模塊的父容器
? ?this.parent = parent;
? ?// 構(gòu)造器
? ?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;
}
// 獲取當(dāng)前元素的方法
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;
}
// 創(chuàng)建新聞組合體容器
// 新聞組合體容器
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、創(chuàng)建一個新聞類(P97)
完成上面的容器類以后,我們就可以去創(chuàng)建我們的新聞類了。
新聞類就沒有子類了,所以也就沒有 add 方法,可聲明也可不聲明。(書中是建議聲明一個空函數(shù))
// 圖片新聞類
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
}
// 創(chuàng)建純文字新聞類
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、把新聞模塊創(chuàng)建出來(P99)
通過使用上面的基類,最終使用以后,我們就可以創(chuàng)建出新聞模塊啦。


14.7、表單的應(yīng)用(P100)
現(xiàn)在想一想,可以用上面的組合模式,把下面的表單填寫內(nèi)容解成基類,然后組合起來。

本章 End,學(xué)習(xí)進度 14/40,加油加油
D1n910 于2021年02月20日 17:19?在南山后海