Benjamin me pediu para esclarecer minha posição, por isso editei meu post anterior e acrescentei mais pensamentos.
Bob Martin é o autor de um grande livro intitulado como Código Limpo. Nesse livro, há um capítulo (Capítulo 6.) chamado Objetos e estruturas de dados, que ele discute as diferenças mais importantes entre objetos e estruturas de dados e afirmações que precisamos escolher entre eles, porque misturá-los é uma péssima idéia.
Essa confusão às vezes leva a estruturas híbridas infelizes que são meio objeto e meia estrutura de dados. Eles têm funções que realizam coisas significativas e também têm variáveis públicas ou acessadores e mutadores públicos que, para todos os efeitos, tornam públicas as variáveis privadas, tentando outras funções externas a usar essas variáveis da maneira que um programa procedural usaria. estrutura de dados.4 Esses híbridos dificultam a adição de novas funções, mas também dificultam a adição de novas estruturas de dados. Eles são os piores dos dois mundos. Evite criá-los. Eles são indicativos de um design confuso cujos autores não têm certeza - ou pior, ignoram - se precisam de proteção contra funções ou tipos.
Eu acho que o DOM é um exemplo desses híbridos de objetos e estrutura de dados. Por exemplo, por DOM, escrevemos códigos como este:
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
O DOM deve ser claramente uma estrutura de dados em vez de um híbrido.
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();
A estrutura do jQuery é uma série de procedimentos, que podem selecionar e modificar uma coleção de nós DOM e fazer muitas outras coisas. Como Laurent apontou em seu post, o jQuery é algo assim:
html(select("#body"), "<p>hello</p>");
Os desenvolvedores do jQuery mesclaram todos esses procedimentos em uma única classe, responsável por todos os recursos listados acima. Por isso, viola claramente o Princípio da Responsabilidade Única e, portanto, é um objeto divino. A única coisa que não quebra nada, porque é uma única classe independente que funciona em uma única estrutura de dados (a coleção de nós DOM). Se adicionarmos subclasses jQuery ou outra estrutura de dados, o projeto entrará em colapso muito rápido. Portanto, acho que não podemos falar sobre oo pelo jQuery, é mais processual do que ooo, apesar de definir uma classe.
O que Laurent afirma é um absurdo completo:
Então o que tudo isso significa? Esse jQuery (como LINQ) não é o antipadrão de objetos de Deus. Em vez disso, é um caso de um padrão muito respeitado chamado Decorator.
O padrão Decorator visa adicionar novas funcionalidades mantendo a interface e não modificando as classes existentes. Por exemplo:
Você pode definir 2 classes que implementam a mesma interface, mas com uma implementação completamente diferente:
/**
* @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
};
Se você tiver métodos que usam apenas a interface comum, poderá definir um ou mais decoradores em vez de copiar e colar o mesmo código entre A e B. Você pode usar esses decoradores mesmo em uma estrutura aninhada.
/**
* @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);
};
Portanto, você pode substituir as instâncias originais pelas instâncias do decorador no código de nível de abstração mais alto.
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(...);
A conclusão de que o jQuery não é um decorador de nada, porque não implementa a mesma interface que Array, NodeList ou qualquer outro objeto DOM. Ele implementa sua própria interface. Os módulos também não são utilizados como decoradores, eles simplesmente substituem o protótipo original. Portanto, o padrão Decorator não é usado em toda a lib do jQuery. A classe jQuery é simplesmente um grande adaptador que nos permite usar a mesma API por muitos navegadores diferentes. De uma perspectiva completa, é uma bagunça completa, mas isso realmente não importa, funciona bem e nós a usamos.
$
função ou umjQuery
objeto.