微吼云上線多路互動直播服務 加速多場景互動直播落地
603
2025-04-03
目錄
1?什么是組合模式
2?主要參與者
3?代碼實現
4?應用實例
4.1 表單驗證
4.1 圖片閱讀器
5?總結
1?什么是組合模式
組合模式允許創建具有屬性的對象,這些對象是原始項目或對象集合。集合中的每個項目本身可以容納其他集合,創建深度嵌套結構。
樹型控件是復合模式的一個完美例子。樹的節點要么包含一個單獨的對象(葉子節點),要么包含一組對象(節點的子樹)。組合模式用于簡單化,一致化對單組件和復合組件的使用;其實它就是一棵樹。
組合模式能對于工作能起到簡化作用,組合對象實現某一操作時,通過遞歸,向下傳遞到所有的組成對象,在存在大批對象時,假如頁面的包含許多擁有同樣功能的對象,只需要操作組合對象即可達到目標。在存在著某種的層次結構,并且其中的一部分要實現某些操作,即可使用組合模式。
組合模式中的所有節點都共享一組通用的屬性和方法,它既支持單個對象,也支持對象集合。這種共同的接口極大地促進了遞歸算法的設計和構建,這種算法可以對復合集合中的每個對象進行迭代。
實例場景:
1 自然界中的各種樹,樹長在大地人,樹頭(樹根),即是入口點,這棵樹頭向上生長,即有自己的葉子,又有自己的子樹枝,某樹枝還有自己的葉子,跟子樹枝。
2? 操作系統目錄結構、公司部門組織架構、國家省市縣等,像這么看起來復雜的現象,都可以使用組合模式,即部分-整體模式來操作。
2?主要參與者
參與該模式的對象有:
Component :聲明組成中對象的接口。
Leaf :代表構圖中的葉子對象,一個葉子沒有子對象。
Composite :表示組成中的分支(或子樹),維護一個子組件的集合。
3?代碼實現
在下邊的代碼中,Node(節點)對象創建了一個樹狀結構。每個節點都有一個名字和4個方法:add、remove、getChild和hasChildren。這些方法被添加到Node的原型中。這減少了對內存的要求,因為這些方法現在被所有節點共享。Node是完全遞歸的,不需要單獨的Component或Leaf對象。
通過向父節點添加節點來構建一個小型的復合樹。一旦完成,我們調用traverse,它將遍歷樹中的每個節點,并顯示其名稱和深度(通過縮進顯示)。日志函數用來記錄和顯示結果。
var Node = function(name) {
this.children = [];
this.name = name;
}
Node.prototype = {
add: function(child) {
this.children.push(child);
},
remove: function(child) {
var length = this.children.length;
for (var i = 0; i < length; i++) {
if (this.children[i] === child) {
this.children.splice(i, 1);
return;
}
}
},
getChild: function(i) {
return this.children[i];
},
hasChildren: function() {
return this.children.length > 0;
}
}
// 使用遞歸遍歷一個樹
function traverse(indent, node) {
log.add(Array(indent++).join("--") + node.name);
for (var i = 0, len = node.children.length; i < len; i++) {
traverse(indent, node.getChild(i));
}
}
// 日志函數記錄和打印結果
var log = (function() {
var log = "";
return {
add: function(msg) {
log += msg + "\n";
},
show: function() {
console.info("%c%s", "color:red; font-size:18px", log);
log = "";
}
}
})();
function run() {
var tree = new Node("root");
var left = new Node("left")
var right = new Node("right");
var leftleft = new Node("leftleft");
var leftright = new Node("leftright");
var rightleft = new Node("rightleft");
var rightright = new Node("rightright");
tree.add(left);
tree.add(right);
tree.remove(right); // 刪除節點
tree.add(right);
left.add(leftleft);
left.add(leftright);
right.add(rightleft);
right.add(rightright);
traverse(1, tree);
log.show();
}
run();
4?應用實例
4.1 表單驗證
演示地址:https://www.albertyy.com/2020/8/Component1.html
表單驗證中,需要做的工作是表單的保存、恢復和驗證表單中的值,然而表單的數量是未知數,類型是未知數,只有功能能確定,在這種情況下,使用組合模式無疑最好,通過給每個表單添加功能,然后一個表單對象組合起來,通過操作表單對象即可達到操作表單。
//存儲的值
var value_content = {};
function setCookie(name, value) {
value_content[name] = value;
}
function getCookie(name) {
return value_content[name];
}
//表單組合對象
var CompositeForm = function(id, method, action) {
this.formComponents = [];
this.element = document.createElement('form');
this.element.id = id;
this.element.method = method || 'POST';
this.element.action = action || '#';
}
CompositeForm.prototype.add = function(child) {
this.formComponents.push(child);
this.element.appendChild(child.getElement());
}
CompositeForm.prototype.remove = function(child) {
for (var i = 0, len = this.formComponents.length; i < len; i++) {
if (child == this.formComponents[i]) {
this.formComponents.splice(i, 1);
break;
}
}
}
CompositeForm.prototype.getChild = function(i) {
return this.formComponents[i];
}
CompositeForm.prototype.save = function() {
for (var i = 0, len = this.formComponents.length; i < len; i++) {
this.formComponents[i].save();
}
}
CompositeForm.prototype.restore = function() {
for (var i = 0, len = this.formComponents.length; i < len; i++) {
this.formComponents[i].restore();
}
}
CompositeForm.prototype.getElement = function() {
return this.element;
}
//接口方法
var Field = function(id) {
this.id = id;
this.element;
this.content;
};
Field.prototype.add = function() {};
Field.prototype.remove = function() {};
Field.prototype.getChild = function() {};
Field.prototype.save = function() {
setCookie(this.id, this.getValue());
};
Field.prototype.getElement = function() {
return this.element;
}
Field.prototype.getValue = function() {
throw new Error('錯誤');
}
Field.prototype.restore = function() {
this.content.value = getCookie(this.id);
};
//繼承方法
function extend(subClass, superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
subClass.superclass = superClass.prototype;
if (superClass.prototype.constructor == Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}
//輸入框
var InputField = function(id, label) {
Field.call(this, id);
this.input = document.createElement('input');
this.content = this.input;
this.label = document.createElement('label');
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode);
this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'input-field';
this.element.appendChild(this.label);
this.element.appendChild(this.input);
}
extend(InputField, Field);
InputField.prototype.getValue = function() {
return this.input.value;
};
//文本框
var TextareaField = function(id, label) {
Field.call(this, id);
this.textarea = document.createElement('textarea');
this.content = this.textarea;
this.label = document.createElement('label');
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode);
this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'input-field';
this.element.appendChild(this.label);
this.element.appendChild(this.textarea);
};
extend(TextareaField, Field);
TextareaField.prototype.getValue = function() {
return this.textarea.value;
};
//選擇框
var SelectField = function(id, label) {
Field.call(this, id);
this.select = document.createElement('select');
this.select.options.add(new Option("sfs", "sfs"));
this.select.options.add(new Option("111", "2222222222")); //這邊value會改變
this.content = this.select;
this.label = document.createElement('label');
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode);
this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'input-field';
this.element.appendChild(this.label);
this.element.appendChild(this.select);
};
extend(SelectField, Field);
SelectField.prototype.getValue = function() {
return this.select.options[this.select.options.selectedIndex].value;
};
//表單域
var CompositeFieldset = function(id, legendText) {
this.components = {};
this.element = document.createElement('fieldset');
this.element.id = id;
if (legendText) {
this.legend = document.createElement('legend');
this.legend.appendChild(document.createTextNode(legendText));
this.element.appendChild(this.legend);
}
};
CompositeFieldset.prototype.add = function(child) {
this.components[child.getElement().id] = child;
this.element.appendChild(child.getElement());
};
CompositeFieldset.prototype.remove = function(child) {
delete this.components[child.getElement().id];
};
CompositeFieldset.prototype.getChild = function(id) {
if (this.components[id] != undefined) {
return this.components[id];
} else {
return null;
}
};
CompositeFieldset.prototype.save = function() {
for (var id in this.components) {
if (!this.components.hasOwnProperty(id))
continue;
this.components[id].save();
}
};
CompositeFieldset.prototype.restore = function() {
for (var id in this.components) {
if (!this.components.hasOwnProperty(id))
continue;
this.components[id].restore();
}
};
CompositeFieldset.prototype.getElement = function() {
return this.element;
};
//用組合模式匯合起來
var contactForm = new CompositeForm('contact-form', 'POST', 'test');
var nameFieldset = new CompositeFieldset('name-fieldset');
nameFieldset.add(new InputField('first-name', 'First Name'));
nameFieldset.add(new InputField('last-name', 'Last Name'));
contactForm.add(nameFieldset);
var addressFieldset = new CompositeFieldset('address-fieldset');
addressFieldset.add(new InputField('address', 'Address'));
addressFieldset.add(new InputField('city', 'City'));
addressFieldset.add(new SelectField('state', 'State'));
addressFieldset.add(new InputField('zip', 'Zip'));
contactForm.add(addressFieldset);
contactForm.add(new TextareaField('comments', 'Comments'));
document.body.appendChild(contactForm.getElement());
function a() {
contactForm.save();
}
function b() {
contactForm.restore();
}
4.1 圖片閱讀器
演示地址:https://www.albertyy.com/2020/8/Component2.html
圖片閱讀器與表單驗證基本一樣,通過匯合操作圖片。
//圖片庫
var DynamicGallery = function(id) {
this.children = [];
this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'dynamic-gallery';
};
DynamicGallery.prototype = {
add: function(child) {
this.children.push(child);
this.element.appendChild(child.getElement());
},
remove: function(child) {
for (var node, i = 0; node = this.getChild(i); i++) {
if (node == child) {
this.children.splice(i, 1);
break;
}
}
this.element.removeChild(chld.getElement());
},
getChild: function(i) {
return this.children[i];
},
hide: function() {
for (var i = 0, node; node = this.getChild(i); i++) {
node.hide();
}
this.element.style.display = 'none';
},
show: function() {
this.element.style.display = 'block';
for (var i = 0, node; node = this.getChild(i); i++) {
node.show();
}
},
getElement: function() {
return this.element;
}
};
//單個圖片
var GalleryImage = function(src) {
this.element = document.createElement('img');
this.element.className = 'gallery-image';
this.element.src = src;
};
GalleryImage.prototype = {
add: function() {},
remove: function() {},
getChild: function() {},
hide: function() {
this.element.style.display = 'none';
},
show: function() {
this.element.style.display = '';
},
getElement: function() {
return this.element;
}
};
//匯合起來
var topGallery = new DynamicGallery('top-gallery');
topGallery.add(new GalleryImage('img/1.jpg'));
topGallery.add(new GalleryImage('img/2.jpg'));
topGallery.add(new GalleryImage('img/3.jpg'));
var vacationPhotos = new DynamicGallery('vacation-photos');
for (var p = 0; p < 30; p++) {
vacationPhotos.add(new GalleryImage('img/3.jpg'));
}
topGallery.add(vacationPhotos);
document.body.appendChild(topGallery.getElement());
function a() {
topGallery.hide();
}
function b() {
topGallery.show();
}
5?總結
組合模式通過簡單的操作就能達到復雜的效果,一個操作通過遍歷遞歸傳遞這個操作。不過組合模式的弱點也在于此,如果層次過多,則性能將受到影響。
組合模式應用需要符合兩個條件,一是產生遞歸,二是具有相同的動作。
今天的學習就到這里,你可以使用今天學習的技巧來改善一下你曾經的代碼,如果想繼續提高,歡迎關注我,每天學習進步一點點,就是領先的開始。如果覺得本文對你有幫助的話,歡迎,評論,轉發!!!
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。