O código de organização vai nos salvar de muita dor. Usando as características da programação Object Oriented, podemos empregar certos padrões de design para conseguir uma melhor legibilidade, reduzir a redundância e criar abstracções, se necessário. Um desses padrões é o padrão de fábrica.
O padrão de fábrica é um tipo de padrão Object Oriented que segue a metodologia DRY. Como o nome sugere, instâncias de objetos são criadas usando uma fábrica para fazer o objeto necessário para nós.
Vejamos um exemplo muito simples de usar o padrão de fábrica para montar um objeto alligator
. Para fazer isso precisamos primeiro fazer fábricas que criam as peças alligator
para nós:
class TailFactory { constructor(props) { this.tailLength = props.tailLength; }};class TorsoFactory { constructor(props) { this.color = props.color; }};class HeadFactory { constructor(props) { this.snoutLenth = props.snoutLenth; }};
Agora, criamos uma classe que atua como um intermediário entre as classes das fábricas reais e o usuário. Vamos chamar isso de ReptilePartFactory
:
class ReptilePartFactory { constructor(type, props) { if(type === "tail") return new TailFactory(props); if(type === "torso") return new TorsoFactory(props); if(type === "head") return new HeadFactory(props); }};
Vamos agora montar o jacaré real e usar o ReptilePartFactory
para obter as peças necessárias para nós:
let alligator = {};let alligatorProps = { tailLength : 2.5, color: "green", snoutLenth: 1};//gets a tail from the tail factoryalligator.tail = new ReptilePartFactory("tail", alligatorProps); //gets a torso from the torso factoryalligator.torso = new ReptilePartFactory("torso", alligatorProps);//gets a head from the head factoryalligator.head = new ReptilePartFactory("head", alligatorProps);
Vejamos o padrão acima, parece que poderíamos usar o mesmo ReptilePartFactory
para criar peças para objetos parecidos com jacaré. As fábricas em segundo plano nunca teriam que saber sobre a natureza do objeto final.
Assim, usar o padrão de fábrica nos dá certas vantagens:
- Criação de objetos dinâmicos: Pode ser usado em casos em que o tipo do objeto é decidido em tempo de execução.
- Abstração: O usuário nunca precisa realmente acessar o construtor do objeto real.
- Reusabilidade/Manutenção: As mesmas fábricas podem ser usadas para objetos similares e isso nos permite adicionar/remover novas classes de objetos facilmente sem alterar muito código.
Agora temos algum entendimento do padrão de fábrica, vamos explorar um pouco sobre escrever melhor o padrão de fábrica.
O exemplo acima usa um if-ladder para descobrir qual fábrica chamar com base no input do usuário. Esta é uma implementação simples, intuitiva e não muito aberta a mudanças. Se tivermos novas peças para adicionar mais tarde, então teremos que perturbar o ReptilePartFactory
. Isto é uma violação dos princípios da SOLID, que diz “As entidades de software (classes, módulos, funções, etc.) devem estar abertas para extensão, mas fechadas para modificação”.
Como armazenar as classes de fábrica em um objeto e chamar a fábrica da peça requerida usando a peça que queremos como chave? Primeiro teríamos que registrar as fábricas, seria tão simples como:
let registeredPartFactories = {};registeredPartFactories = class TailFactory{ ...};registeredPartFactories = class TorsoFactory { ...};registeredPartFactories = class HeadFactory { ...};
E agora, a camada abstrata pode chamar as fábricas assim:
class ReptilePartFactory { constructor(type, props) { return new registeredPartFactories(props); }};
Esta abordagem é muito mais limpa e permite expandir nossas fábricas sem afetar o código no ReptilePartFactory
.
Em conclusão
Existem vários outros padrões orientados a objetos que também aumentam a legibilidade e qualidade. Portanto, antes de usar o padrão de fábrica, verifique se há uma necessidade real para ele. Se você vai criar tipos similares de objetos repetidamente e também precisa de uma camada para criar novas instâncias usando esses objetos enquanto fornece algum nível de abstração para a lógica de criação, então sim – o padrão de fábrica é uma boa opção.