Como criar código reutilizável em JavaScript usando padrões de design
Se você quiser criar código JavaScript reutilizável ou colaborar com uma equipe de desenvolvedores, precisará saber como usar e identificar os diferentes padrões de design na linguagem.
Em JavaScript, o termo padrão de design se refere a uma maneira específica de escrever código e geralmente é considerado um modelo de programação. O interessante é que o rótulo “padrão de design” pode ser aplicado a qualquer coisa, desde um aplicativo inteiro até um simples bloco de código.
O padrão de design é um tópico amplo, mas ao entender o padrão do módulo e o método de fábrica, você deve se familiarizar com ele.
O Padrão do Módulo
Os módulos JavaScript foram introduzidos em 2009, com a versão ES5 da linguagem de programação. Usando módulos, os desenvolvedores agora podem criar pedaços de código personalizados e exportá-los para serem usados em outras seções de um aplicativo JavaScript.
A Estrutura Básica do Padrão do Módulo
(function(){
//Declare private variables and functions
//Declare and return public variables and functions
})();
No exemplo acima, os padrões de módulo são sempre incluídos em uma expressão de função imediatamente chamada (IIFE). Isso significa que um padrão de módulo é executado assim que é definido. O importante a observar é que o padrão de módulo consiste em duas seções distintas.
A primeira seção é usada para declarar variáveis e funções privadas, que só podem ser acessadas dentro do escopo do padrão de módulo.
A segunda seção consiste em um valor de retorno que inclui variáveis públicas e funções que podem ser acessadas fora do escopo do padrão de módulo.
Usando o padrão de módulo para criar um aplicativo
Considere um aplicativo simples, como um gerenciador de tarefas. Usando o padrão de módulo, você precisará criar módulos personalizados para cada seção. Isso pode incluir:
- Um controlador de tarefa
- Um controlador de IU
- Um controlador de armazenamento
- Um controlador de aplicativo
O controlador de tarefa será usado para criar cada nova tarefa. O controlador de IU será usado para controlar as funções relacionadas à IU, como ouvir o clique de um botão ou alterar o que está sendo exibido. O controlador de armazenamento será usado para salvar cada nova tarefa em um banco de dados. O módulo de aplicativo será usado para executar o aplicativo.
Usando o padrão de módulo para criar um exemplo de controlador de IU
const UIController = ( function() {
//the private section of the module
let component = 'Replacement Text';
const changeComponent = function() {
//change all the h1 text to what is in the component variable above
const element = document.querySelector('h1');
element.textContent = component;
}
//the public section of the module
return{
callChangeComponent: function() {
changeComponent();
}
}
})();
O exemplo acima mostra claramente as duas seções que são encontradas em um padrão de módulo – privado e público.
Na seção privada da função, a variável do componente e a função changeComponent são ambas privadas. Portanto, se você quiser alterar todo o texto h1 em uma página da web, receberá um erro se escrever o código a seguir.
Maneira incorreta de invocar o exemplo changeComponent
UIController.changeComponent();
A mensagem de erro irá declarar explicitamente que changeComponent () não é uma função da função UIController. Essa é a beleza do padrão de módulo; as variáveis e funções criadas na seção privada nunca serão acessadas diretamente fora do escopo dessa função.
Embora as variáveis privadas não possam ser acessadas diretamente, elas podem, no entanto, ser acessadas indiretamente (na seção pública). Uma lição do exemplo do controlador de IU acima é que a seção pública no padrão do módulo é sempre marcada pela propriedade return.
Dentro dos parâmetros da propriedade return, agora podemos obter acesso indireto à função changeComponent. Agora podemos usar a seguinte linha de código (com o padrão de módulo acima) para alterar efetivamente todo o texto h1 em uma página da web de destino para “Texto de Substituição”.
Maneira correta de invocar o exemplo changeComponent
UIController.callChangeComponent();
O Padrão de Fábrica
O padrão de fábrica (também conhecido como método de fábrica) é outro padrão de design JavaScript popular. O padrão de módulo brilha quando o encapsulamento de dados é necessário, e o padrão de fábrica é mais útil nos casos em que estamos lidando com uma coleção de objetos diferentes que são semelhantes em alguns aspectos.
Voltando ao nosso gerenciador de tarefas acima; se permitíssemos que o usuário atribuísse um tipo a cada tarefa criada, poderíamos criar esse aspecto do aplicativo (de forma bastante eficiente) usando o padrão de fábrica
Usando o padrão de fábrica para atribuir um exemplo de tipo de tarefa
//Factory pattern function
const TaskFactory = function(){
this.createTask = function(name, type){
let task;
//check the type the user selected
if(type === 'urgent'){
task = new UrgentTask(name);
}else if(type === 'trivial'){
task = new TrivialTask(name);
}
//set the type selected in the if statement to the one received as a property
task.type = type;
//used to print the task and its type to the console
task.define = function(){
console.log(`${this.name} (${this.type}): ${this.priority}`)
}
return task
}
}
O código acima usa o método de fábrica para criar novas tarefas, verificar o tipo (urgente ou trivial) e atribuir a propriedade apropriada antes de imprimir a nova tarefa no console.
A função interna createTask define o cenário para várias tarefas a serem criadas simultaneamente, mas antes de tentarmos criar qualquer nova tarefa, há algum código adicional que precisamos incluir nesta seção do projeto.
No código acima, estamos criando uma nova UrgentTask ou uma nova Trivialtask se uma condição específica for atendida. No entanto, não há nenhuma função ou classe com esses nomes em nosso projeto – esse problema pode ser facilmente resolvido introduzindo o código a seguir em nosso projeto.
Criar tipos de tarefas urgentes e triviais
//Create the urgent task type
const UrgentTask = function(name){
this.name = name;
this.priority = "as soon as possible"
}
//create the trivial task type
const TrivialTask = function(name){
this.name = name;
this.priority = "when you can"
}
Por causa do código acima, agora podemos atribuir a propriedade UrgentTask ou TrivialTask a cada nova tarefa criada. O próximo passo agora é criar uma nova tarefa, mas antes disso, precisamos criar um banco de dados para armazenar cada nova tarefa à medida que ela é criada.
Dado que a criação de um banco de dados é um artigo inteiro em si, substituiremos um banco de dados por uma estrutura de dados (um array).
Exemplo de criação de matriz
//create an array to host the different task
const task = [];
Agora podemos finalmente criar uma nova tarefa.
Exemplo de criação de novas tarefas
//create two new tasks
const factory = new TaskFactory();
task.push(factory.createTask('Clean the house', 'urgent'));
task.push(factory.createTask('Reach level 30 in Candy Crush', 'trivial'));
Com o código acima, agora você pode criar duas novas tarefas usando a função TaskFactory que criamos inicialmente. Quando criamos cada nova tarefa, as propriedades (nome e tipo) são passadas para a função createTask, que está localizada na função TaskFactory que criamos usando o padrão de fábrica.
Depois que cada tarefa percorrer o TaskFactory e a propriedade de tipo apropriada for atribuída a ela. Em seguida, ele é enviado para a matriz de tarefas que criamos anteriormente.
Nosso único dilema agora é como saber se essas duas tarefas foram criadas ou se nosso padrão de fábrica funcionou? Se tivéssemos usado um banco de dados, poderíamos simplesmente verificar o banco de dados para ver se duas novas tarefas foram criadas.
Volte para o "Usando o padrão de fábrica para atribuir um exemplo de tipo de tarefa" acima, diretamente abaixo do comentário "usado para imprimir a tarefa e seu tipo no console", há uma pequena função "task.define" que foi criada para imprima cada tarefa na matriz no console usando o seguinte método de matriz .
//print each task to the console
task.forEach(function(task){
task.define();
});
Você deve ver a seguinte saída sendo exibida em seu console.
Clean the house (urgent): as soon as possible
Reach level 30 in Candy Crush (trivial): when you can
Agora você pode usar padrões de design em seus projetos JavaScript
Neste estágio, você deve compreender os padrões de design em JavaScript e como os padrões de design podem ser usados para criar código reutilizável e facilitar a vida de todos os desenvolvedores envolvidos em um projeto.
Agora que você sabe como funcionam dois padrões de design JavaScript populares, deve ser capaz de aplicá-los com eficiência para desenvolver um aplicativo.
Crédito da imagem: Alltechbuzz / Pixabay