---
description: http://www.giaosucan.com/2018/07/chem-gio-ve-javascript-design-pattern.html
---

# Chém gió về JavaScript Design Pattern - Part 3

Sau phần 1 và 2, bài này tiếp tục giới thiệu một số JS design patterns thông dụng, rất có ích trong việc lập trình JS\


### Bridge Pattern

Nếu bạn muốn lập trình JS theo hướng sự kiện, event-driven programming, hoặc xây dựng JavaScript API, pattern này khác hữu dụng, khiến code của bạn gọn nhẹ, dễ bảo trìDưới đây là 1 số ví dụ về Bridge PatternEvent ListenersKhi lập trình xử lý sự kiện, bạn quen thuộc với các hàm callback. Ví dụ, như user click vào 1 nút thì 1 hàm sẽ được gọiaddEvent(element, 'click', getBeerById);\
function getBeerById(e) {    var id = this.id;    asyncRequest('GET', 'beer.uri?id=' + id, function (resp) {        // Callback response.        console.log('Requested Beer: ' + resp.responseText);    });}Với cách code như trên, event object sẽ được pass vào method getBeerById, object ở đây có thể là 1 nút, 1 text box trên web page mà user click vào. Sau đó method này sẽ lấy thuộc tính id của object để xử lý tiếp. Tuy nhiên nếu như object không có thuộc tính id sẽ gây lỗi, cách truyền tham số trên không optimize, ngoài ra bạn sẽ gặp khó khăn trong việc lấy kết quả trả về khi gọi method trên trong chương trình của bạn.Dưới đây là cách cải tiến, truyền thẳng id vào method, kết quả trả về qua hàm callbackfunction getBeerById(id, callback) {    // Make request for beer by ID, then return the beer data.    asyncRequest('GET', 'beer.uri?id=' + id, function (resp) {        // callback response        callback(resp.responseText);    });}\
Cách code trên thì bạn có thể gọi API getBeerById ở bất kì đâu như ở dướigetBeerById(this.id, function (beer) {    console.log('Requested Beer: ' + beer);});\
Cách code trên được mình sử dụng khá nhiều và thấy rất hiệu quả, các bạn có thể tham khảo

### Composite Pattern

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)Ví dụ class CompositeFormvar 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 fieldField 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 compositevar 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àoVí 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ư sauvar 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);\
Trên đây 2 pattern khá hữu ích trong JS, bài tiếp sẽ giới thiệu nhiều pattern khác độc đáo hơn

![](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)
