Alguém pode esclarecer a diferença entre uma função de construtor e uma função de fábrica em Javascript.
Quando usar um em vez do outro?
fonte
Alguém pode esclarecer a diferença entre uma função de construtor e uma função de fábrica em Javascript.
Quando usar um em vez do outro?
A diferença básica é que uma função construtora é usada com a new
palavra - chave (que faz com que o JavaScript crie automaticamente um novo objeto, defina this
dentro da função para esse objeto e retorne o objeto):
var objFromConstructor = new ConstructorFunction();
Uma função de fábrica é chamada como uma função "regular":
var objFromFactory = factoryFunction();
Mas, para ser considerada uma "fábrica", seria necessário retornar uma nova instância de algum objeto: você não a chamaria de função "fábrica" se apenas retornasse um valor booleano ou algo assim. Isso não acontece automaticamente como com new
, mas permite mais flexibilidade para alguns casos.
Em um exemplo muito simples, as funções mencionadas acima podem ser algo como isto:
function ConstructorFunction() {
this.someProp1 = "1";
this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };
function factoryFunction() {
var obj = {
someProp1 : "1",
someProp2 : "2",
someMethod: function() { /* whatever */ }
};
// other code to manipulate obj in some way here
return obj;
}
É claro que você pode tornar as funções de fábrica muito mais complicadas do que esse exemplo simples.
Uma vantagem das funções de fábrica é quando o objeto a ser retornado pode ter vários tipos diferentes, dependendo de algum parâmetro.
someMethod
os objetos devolvidos pela fábrica e é aí que fica um pouco nebuloso. Dentro da função de fábrica, se alguém o fizervar obj = { ... , someMethod: function() {}, ... }
, isso levaria a cada objeto retornado, mantenha uma cópia diferente dasomeMethod
qual é algo que talvez não desejemos. É aí que o usonew
eprototype
a função de fábrica ajudariam.new
com a função construtora; Eu pensei que era onde seria necessário ver um exemplo de como substituir construtores por funções de fábrica e é aí que eu achava que a consistência nos exemplos era necessária. De qualquer forma, a resposta é informativa o suficiente. Esse era apenas um ponto que eu queria levantar, não que eu estivesse diminuindo a qualidade da resposta de alguma forma.new
internamente ouObject.create()
criar um objeto com um protótipo específico.Benefícios do uso de construtores
A maioria dos livros ensina você a usar construtores e
new
this
refere-se ao novo objetoAlgumas pessoas gostam da maneira como
var myFoo = new Foo();
lê.Desvantagens
Os detalhes da instanciação vazam para a API de chamada (por meio do
new
requisito), para que todos os chamadores estejam fortemente acoplados à implementação do construtor. Se você precisar da flexibilidade adicional da fábrica, precisará refatorar todos os chamadores (reconhecidamente o caso excepcional, e não a regra).Esquecer
new
é um bug tão comum, você deve considerar fortemente adicionar uma verificação padrão para garantir que o construtor seja chamado corretamente (if (!(this instanceof Foo)) { return new Foo() }
). EDIT: Desde ES6 (ES2015), você não pode esquecernew
umclass
construtor, ou o construtor lançará um erro.Se você fizer o
instanceof
verificação, deixa ambiguidade quanto a ser ou nãonew
necessário. Na minha opinião, não deveria ser. Você efetivamente interrompeu onew
requisito, o que significa que você pode apagar a desvantagem nº 1. Mas você terá uma função de fábrica com apenas o nome , com clichê adicional, uma letra maiúscula e menos flexívelthis
contexto .Construtores quebram o Princípio Aberto / Fechado
Mas minha principal preocupação é que viole o princípio de abrir / fechar. Você começa a exportar um construtor, os usuários começam a usá-lo e, depois, no caminho, percebe que precisa da flexibilidade de uma fábrica (por exemplo, para alternar a implementação para usar conjuntos de objetos ou para instanciar contextos de execução ou para ter mais flexibilidade de herança usando OO prototípico).
Você está preso, no entanto. Você não pode fazer a alteração sem quebrar todo o código que chama seu construtor com
new
. Você não pode mudar para usar pools de objetos para obter ganhos de desempenho, por exemplo.Além disso, o uso de construtores fornece uma enganosa
instanceof
que não funciona em contextos de execução e não funciona se o seu protótipo de construtor for trocado. Também falhará se você começar retornandothis
do construtor e depois mudar para exportar um objeto arbitrário, o que você teria que fazer para habilitar o comportamento de fábrica no construtor.Benefícios do uso de fábricas
Menos código - não requer clichê.
Você pode retornar qualquer objeto arbitrário e usar qualquer protótipo arbitrário - oferecendo mais flexibilidade para criar vários tipos de objetos que implementam a mesma API. Por exemplo, um media player que pode criar instâncias de HTML5 e flash players, ou uma biblioteca de eventos que pode emitir eventos DOM ou soquetes da web. As fábricas também podem instanciar objetos em contextos de execução, tirar proveito dos pools de objetos e permitir modelos de herança prototípica mais flexíveis.
Você nunca precisaria converter de uma fábrica para um construtor; portanto, a refatoração nunca será um problema.
Nenhuma ambiguidade sobre o uso
new
. Não. (Isso fará com quethis
se comporte mal, veja o próximo ponto).this
se comporta como normalmente faria - para que você possa usá-lo para acessar o objeto pai (por exemplo, insideplayer.create()
,this
refere-se aplayer
, como qualquer outra invocação de método faria.call
eapply
também reatribuirthis
, conforme o esperado. Se você armazenar protótipos no objeto pai, isso pode ser uma ótima maneira de trocar dinamicamente a funcionalidade e permitir um polimorfismo muito flexível para a instanciação do objeto.Nenhuma ambiguidade em capitalizar ou não. Não. As ferramentas de cotão reclamarão, e você será tentado a usá
new
-lo e depois desfará o benefício descrito acima.Algumas pessoas gostam do jeito
var myFoo = foo();
ouvar myFoo = foo.create();
leem.Desvantagens
new
não se comporta como o esperado (veja acima). Solução: não use.this
não se refere ao novo objeto (em vez disso, se o construtor for chamado com notação de ponto ou colchete, por exemplo, foo.bar () -this
refere-se afoo
- assim como qualquer outro método JavaScript - veja os benefícios).fonte
new
viola o princípio de abrir / fechar. Consulte medium.com/javascript-scene/… para uma discussão muito maior do que esses comentários permitem.new
palavra - chave, não acredito que anew
palavra - chave realmente forneça legibilidade adicional. Na IMO, parece bobagem pular os bastidores para permitir que os chamadores digitem mais.Um construtor retorna uma instância da classe em que você a chama. Uma função de fábrica pode retornar qualquer coisa. Você usaria uma função de fábrica quando precisar retornar valores arbitrários ou quando uma classe tiver um grande processo de configuração.
fonte
Um exemplo de função do Construtor
new
cria um objeto com prototipagemUser.prototype
e chamaUser
com o objeto criado como seuthis
valor.new
trata uma expressão de argumento para seu operando como opcional:causaria
new
a chamadaUser
sem argumentos.new
retorna o objeto que ele criou, a menos que o construtor retorne um valor de objeto , que é retornado. Este é um caso extremo que, na maior parte, pode ser ignorado.Prós e contras
Objetos criados por funções de construtor herdam propriedades da propriedade do construtor
prototype
e retornam true usando oinstanceOf
operador na função de construtor.Os comportamentos acima podem falhar se você alterar dinamicamente o valor da
prototype
propriedade do construtor depois de já ter usado o construtor. Fazer isso é raro e não pode ser alterado se o construtor tiver sido criado usando aclass
palavra - chave.As funções do construtor podem ser estendidas usando a
extends
palavra - chaveAs funções do construtor não podem retornar
null
como um valor de erro. Como não é um tipo de dados do objeto, é ignorado pornew
.Um exemplo de função de fábrica
Aqui a função de fábrica é chamada sem
new
. A função é totalmente responsável pelo uso direto ou indireto se seus argumentos e o tipo de objeto que ela retornar. Neste exemplo, ele retorna um simples [Objeto de objeto] com algumas propriedades definidas a partir de argumentos.Prós e contras
Oculta facilmente as complexidades de implementação da criação de objetos do chamador. Isso é particularmente útil para funções de código nativo em um navegador.
A função de fábrica nem sempre retorna objetos do mesmo tipo e pode até retornar
null
como um indicador de erro.Em casos simples, as funções de fábrica podem ser simples em estrutura e significado.
Os objetos retornados geralmente não herdam da
prototype
propriedade da função de fábrica e retornamfalse
deinstanceOf factoryFunction
.A função de fábrica não pode ser estendida com segurança usando a
extends
palavra - chave, porque os objetos estendidos herdariam daprototype
propriedade de funções de fábrica, e não daprototype
propriedade do construtor usado pela função de fábrica.fonte
As fábricas são "sempre" melhores. Ao usar linguagens orientadas a objetos,
As implementações (os objetos reais criados com o novo) não são expostas ao usuário / consumidor da fábrica. Isso significa que o desenvolvedor da fábrica pode expandir e criar novas implementações, desde que não rompa o contrato ... e permite que o consumidor da fábrica se beneficie apenas da nova API sem precisar alterar o código ... se eles usaram new e uma implementação "nova" aparece, eles precisam mudar todas as linhas que usam "new" para usar a "nova" implementação ... com a fábrica, seu código não muda ...
Fábricas - melhor do que qualquer outra coisa - a estrutura da primavera é completamente construída em torno dessa idéia.
fonte
As fábricas são uma camada de abstração e, como todas as abstrações, têm um custo de complexidade. Ao encontrar uma API baseada na fábrica, descobrir qual é a fábrica para uma determinada API pode ser um desafio para o consumidor da API. Com os construtores, a descoberta é trivial.
Ao decidir entre os médicos e as fábricas, você precisa decidir se a complexidade é justificada pelo benefício.
Vale ressaltar que os construtores Javascript podem ser fábricas arbitrárias retornando algo diferente disso ou indefinido. Assim, em js, você pode obter o melhor dos dois mundos - API detectável e pool / cache de objetos.
fonte
new
, Alterando o comportamento dethis
, Alterando o valor de retorno, Conectando um ref de protótipo, Ativandoinstanceof
(que está e não deve ser usado para essa finalidade). Aparentemente, todos esses são "recursos". Na prática, eles prejudicam a qualidade do seu código.Para as diferenças, Eric Elliott esclareceu muito bem,
Mas para a segunda pergunta:
Se você é proveniente do plano de fundo orientado a objetos, a função Constructor parece mais natural para você. Dessa forma, você não deve esquecer de usar a
new
palavra-chave.fonte