---
description: >-
  https://app.gitbook.com/@javascriptuse/s/advanced/chem-gio-ve-javascript-design-pattern-part-3
---

# Composite Pattern (ok)

Trước hết cũng cần phải hiểu composite là cái gì. Đại loại là cấu trúc dạng cây, ông bà , bố mẹ, đến con cháu, nhánh cuối cùng không có nhánh con thì gọi là Leaf, còn lại là Composite hếtÝ tưởng của composite là group các objects lại theo dạng cha, con như trên. Điều này cần thiết khi bạn phải xử lý 1 số lượng lớn các objects. Pattern này được thiết kế để tổ chức object và pass operation từ level cao đến level thấp hơn. Sử dụng pattern này cho phép bạn tạo object loosely coupled hơnVí dụ về pattern này, tưởng tượng bạn cần tạo 1 form nhập liệu, trong đó các input được validate và lưu trữ. Tuy nhiên tùy vào user, form này có thể thay đổi chẳng hạn user thuộc loại doanh nghiệp thì sẽ không hiển thị text box website chẳng hạn. Tức là bạn cần phải tạo ra một dynamic formRõ ràng, là không tạo form theo kiểu hardcode được, và composite pattern phát huy tác dụng của nó trong trường hợp nàyTa có thể tạo composite object như sau, top level chính là cái form của bạn Bạn sẽ tạo ra 1 form cho phép add thêm hoặc remove các field mà không cần phải viết lại codeImplement code theo class diagram như sau

![](https://lh3.googleusercontent.com/bzcLCcpfeCz_E3XDsXYY9KLaGZTcYl8lDjk-i8Ab96mrRpg0HY2abFZxSt5H7TVrXG56KfukIDvMPh65Nj5dJqyUxssiQ27HPvpVVFR-otuQz6oeKdfRkDGLJ9wSpsCnNi6ztyCBMmLEX314Dw)

![](https://lh5.googleusercontent.com/xp3100mGoiWW6NkVzw2Ol9fmZ_Wl-tJwnS2UQ2lfEecHBCRPz2WPaxaJD8Rgw4OZphGC0NaH8NbzWqfuhPuy0-JnaridV5M-betpChWgx9_ijgPXZRtTHoOed3IBkCKk2ZpNMhHvJlXU2vl4Sw)

![](https://lh6.googleusercontent.com/6IFELrL07hfIHgvVWZRo9kW6Wv8e1bPuARl7hDLww6X8tkh_Prp_NDBgDS4waUnlygQDLx3c4DbaQBV4Dk5aVl5dCQxYePLeqtsvPvemzq43Me9clGVDDRtnbydRqJMqlRO9Qrbn18HFm1SJWw)

![](https://lh3.googleusercontent.com/f-4DfID2ItcGi4rxOySTpgWJkRU_B6D3Cy8Qob7Tve9VCa1JJ-Es4yGwOOBo8C2Yn5ujkdkb8_d-bxfrpu3Uqi2bUzgfhdGMrz9TeWFQ6xJ7aUmmunUEh__WATDHz6Y2SW931DE49Cd3fIJecQ)

#### Ví dụ class CompositeForm

```
var CompositeForm = function(id, method, action) { // implements Composite, FormItem
  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) {
  Interface.ensureImplements(child, Composite, FormItem);
  this.formComponents.push(child);
  this.element.appendChild(child.getElement());
};
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.getElement = function() {
  return this.element;
};
```

Các field của form được lưu trong 1 array formComponents nên dễ dàng thêm bớt field Field class (leaf node) không có thuộc tính add, remove, getChild ví nó là Leaf node trong cấu trúc cây composite

```
var Field = function(id) { // implements Composite, FormItem
  this.id = id;
  this.element;
};
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;
};
```

InputField, TextAreaField, SelectField là 3 class đại diên cho 3 GUI component là Input Text. TextArea, Dropdownbox, bạn có thể add các html element vào&#x20;

Ví dụ InputField

```
var InputField = function(id, label) { // implements Composite, FormItem
  Field.call(this, id);
  this.input = document.createElement('input');
  this.input.id = id;
  this.label = document.createElement('label');
  var labelTextNode = document.createTextNode(label);
  this.label.appendChild(labelTextNode);
  this.element = document.createElement('div');
  this.element.className = 'input-field';
  this.element.appendChild(this.label);
  this.element.appendChild(this.input);
};
extend(InputField, Field); // Inherit from Field.
InputField.prototype.getValue = function() {
  return this.input.value;
};
```

Và cuối cùng bạn có thể tạo dynamic form như sau

```
var contactForm = new CompositeForm('contact-form', 'POST', 'contact.php');
contactForm.add(new InputField('first-name', 'First Name'));
contactForm.add(new InputField('last-name', 'Last Name'));
contactForm.add(new InputField('address', 'Address'));
contactForm.add(new InputField('city', 'City'));
contactForm.add(new SelectField('state', 'State', stateArray));
// var stateArray =[{'al', 'Alabama'}, ...];
contactForm.add(new InputField('zip', 'Zip'));
contactForm.add(new TextareaField('comments', 'Comments'));
addEvent(window, 'unload', contactForm.save);
```

Full

```
var CompositeForm = function(id, method, action) { // implements Composite, FormItem
  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) {
  Interface.ensureImplements(child, Composite, FormItem);
  this.formComponents.push(child);
  this.element.appendChild(child.getElement());
};
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.getElement = function() {
  return this.element;
};
var Field = function(id) { // implements Composite, FormItem
  this.id = id;
  this.element;
};
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;
};
var InputField = function(id, label) { // implements Composite, FormItem
  Field.call(this, id);
  this.input = document.createElement('input');
  this.input.id = id;
  this.label = document.createElement('label');
  var labelTextNode = document.createTextNode(label);
  this.label.appendChild(labelTextNode);
  this.element = document.createElement('div');
  this.element.className = 'input-field';
  this.element.appendChild(this.label);
  this.element.appendChild(this.input);
};
extend(InputField, Field); // Inherit from Field.
InputField.prototype.getValue = function() {
  return this.input.value;
};
var contactForm = new CompositeForm('contact-form', 'POST', 'contact.php');
contactForm.add(new InputField('first-name', 'First Name'));
contactForm.add(new InputField('last-name', 'Last Name'));
contactForm.add(new InputField('address', 'Address'));
contactForm.add(new InputField('city', 'City'));
contactForm.add(new SelectField('state', 'State', stateArray));
// var stateArray =[{'al', 'Alabama'}, ...];
contactForm.add(new InputField('zip', 'Zip'));
contactForm.add(new TextareaField('comments', 'Comments'));
addEvent(window, 'unload', contactForm.save);
```
