Benjamin yêu cầu tôi làm rõ vị trí của mình, vì vậy tôi đã chỉnh sửa bài viết trước của mình và thêm những suy nghĩ khác.
Bob Martin là tác giả của một cuốn sách tuyệt vời có tựa đề là Clean Code. Trong cuốn sách đó có một chương (Chương 6.) được gọi là các cấu trúc Đối tượng và Dữ liệu, ông thảo luận về sự khác biệt quan trọng nhất giữa các đối tượng và cấu trúc dữ liệu và tuyên bố rằng chúng ta phải chọn giữa chúng, bởi vì trộn chúng là một ý tưởng rất tồi.
Sự nhầm lẫn này đôi khi dẫn đến các cấu trúc lai không may là một nửa đối tượng và một nửa cấu trúc dữ liệu. Chúng có các hàm làm những việc quan trọng và chúng cũng có các biến công khai hoặc các bộ truy cập và bộ biến đổi công khai, với tất cả ý nghĩa và mục đích, làm cho các biến riêng tư công khai, cám dỗ các hàm bên ngoài khác sử dụng các biến đó theo cách mà một chương trình thủ tục sẽ sử dụng cấu trúc dữ liệu.4 Các giống lai như vậy làm cho việc thêm các chức năng mới trở nên khó khăn nhưng cũng làm cho việc thêm các cấu trúc dữ liệu mới trở nên khó khăn. Họ là tồi tệ nhất của cả hai thế giới. Tránh tạo ra chúng. Chúng là dấu hiệu cho thấy một thiết kế lầy lội mà các tác giả của chúng không chắc chắn về điều này hoặc tệ hơn, không biết gì về việc liệu họ có cần bảo vệ khỏi các chức năng hoặc các loại hay không.
Tôi nghĩ DOM là một ví dụ về các giống lai cấu trúc dữ liệu và đối tượng này. Ví dụ: bằng DOM, chúng tôi viết mã như thế này:
el.appendChild(node);
el.childNodes;
// bleeding internals
el.setAttribute(attr, val);
el.attributes;
// bleeding internals
el.style.color;
// at least this is okay
el = document.createElement(tag);
doc = document.implementation.createHTMLDocument();
// document is both a factory and a tree root
DOM nên rõ ràng là một cấu trúc dữ liệu thay vì lai.
el.childNodes.add(node);
// or el.childNodes[el.childNodes.length] = node;
el.childNodes;
el.attributes.put(attr, val);
// or el.attributes[attr] = val;
el.attributes;
el.style.get("color");
// or el.style.color;
factory = new HtmlNodeFactory();
el = factory.createElement(document, tag);
doc = factory.createDocument();
Khung công tác jQuery là một loạt các thủ tục, có thể chọn và sửa đổi một tập hợp các nút DOM và thực hiện nhiều thứ khác. Như Laurent đã chỉ ra trong bài viết của mình, jQuery là một cái gì đó như thế này dưới mui xe:
html(select("#body"), "<p>hello</p>");
Các nhà phát triển của jQuery đã hợp nhất tất cả các quy trình này thành một lớp duy nhất, chịu trách nhiệm cho tất cả các tính năng được liệt kê ở trên. Vì vậy, nó rõ ràng vi phạm Nguyên tắc Trách nhiệm duy nhất và vì vậy nó là một đối tượng của thần. Điều duy nhất bởi vì nó không phá vỡ bất cứ thứ gì, bởi vì nó là một lớp độc lập duy nhất hoạt động trên một cấu trúc dữ liệu duy nhất (tập hợp các nút DOM). Nếu chúng ta thêm các lớp con jQuery hoặc cấu trúc dữ liệu khác, dự án sẽ sụp đổ rất nhanh. Vì vậy, tôi không nghĩ rằng chúng ta có thể nói về oo bằng jQuery, nó khá thủ tục hơn oo mặc dù thực tế là nó định nghĩa một lớp.
Những gì Laurent tuyên bố là hoàn toàn vô nghĩa:
Vì vậy, những gì sẽ làm tất cả có nghĩa gì? JQuery đó (như LINQ) không phải là mô hình chống đối tượng của Chúa. Thay vào đó là một trường hợp của một mẫu rất được tôn trọng gọi là Trang trí.
Mẫu Decorator là về việc thêm chức năng mới bằng cách giữ giao diện và không sửa đổi các lớp hiện có. Ví dụ:
Bạn có thể định nghĩa 2 lớp thực hiện cùng một giao diện, nhưng với cách triển khai hoàn toàn khác nhau:
/**
* @interface
*/
var Something = function (){};
/**
* @argument {string} arg1 The first argument.
* @argument {string} arg2 The second argument.
*/
Something.prototype.doSomething = function (arg1, arg2){};
/**
* @class
* @implements {Something}
*/
var A = function (){
// ...
};
/**
* @argument {string} arg1 The first argument.
* @argument {string} arg2 The second argument.
*/
A.prototype.doSomething = function (arg1, arg2){
// doSomething implementation of A
};
/**
* @class
* @implements {Something}
*/
var B = function (){
// ...
};
/**
* @argument {string} arg1 The first argument.
* @argument {string} arg2 The second argument.
*/
B.prototype.doSomething = function (arg1, arg2){
// doSomething implementation of B
// it is completely different from the implementation of A
// that's why it cannot be a sub-class of A
};
Nếu bạn có các phương thức chỉ sử dụng giao diện chung, thì bạn có thể xác định một hoặc nhiều Trình trang trí thay vì sao chép cùng một mã giữa A và B. Bạn có thể sử dụng các trình trang trí này ngay cả trong cấu trúc lồng nhau.
/**
* @class
* @implements {Something}
* @argument {Something} something The decorated object.
*/
var SomethingDecorator = function (something){
this.something = something;
// ...
};
/**
* @argument {string} arg1 The first argument.
* @argument {string} arg2 The second argument.
*/
SomethingDecorator.prototype.doSomething = function (arg1, arg2){
return this.something.doSomething(arg1, arg2);
};
/**
* A new method which can be common by A and B.
*
* @argument {function} done The callback.
* @argument {string} arg1 The first argument.
* @argument {string} arg2 The second argument.
*/
SomethingDecorator.prototype.doSomethingDelayed = function (done, arg1, arg2){
var err, res;
setTimeout(function (){
try {
res = this.doSomething(o.arg1, o.arg2);
} catch (e) {
err = e;
}
callback(err, res);
}, 1000);
};
Vì vậy, bạn có thể thay thế các thể hiện ban đầu bằng các thể hiện trang trí trong mã mức độ trừu tượng cao hơn.
function decorateWithManyFeatures(something){
var d1 = new SomethingDecorator(something);
var d2 = new AnotherSomethingDecorator(d1);
// ...
return dn;
}
var a = new A();
var b = new B();
var decoratedA = decorateWithManyFeatures(a);
var decoratedB = decorateWithManyFeatures(b);
decoratedA.doSomethingDelayed(...);
decoratedB.doSomethingDelayed(...);
Kết luận rằng jQuery không phải là Công cụ trang trí của bất cứ thứ gì, vì nó không thực hiện cùng một giao diện như Array, NodeList hoặc bất kỳ đối tượng DOM nào khác. Nó thực hiện giao diện riêng của nó. Các mô-đun cũng không được sử dụng làm Trình trang trí, chúng chỉ đơn giản ghi đè lên nguyên mẫu ban đầu. Vì vậy, mẫu Decorator không được sử dụng trong toàn bộ lib lib. Lớp jQuery đơn giản là một bộ điều hợp khổng lồ cho phép chúng ta sử dụng cùng một API bởi nhiều trình duyệt khác nhau. Từ quan điểm oo, nó là một mớ hỗn độn, nhưng điều đó không thực sự quan trọng, nó hoạt động tốt và chúng tôi sử dụng nó.
$
chức năng hoặcjQuery
đối tượng.