A Lei de Demeter, também conhecida como princípio do mínimo conhecimento, é uma diretriz para o design de objetos. Segundo essa lei, um objeto deve limitar suas interações a um número limitado de "amigos íntimos" e evitar conhecer as estruturas internas de outros objetos.
Vou dar um exemplo de código JavaScript que viola a Lei de Demeter e depois mostrar como corrigi-lo. No exemplo, vamos considerar um objeto Carro que tem um objeto Motor:
function Carro() {
this.motor = new Motor();
}
function Motor() {
this.revolucoesPorMinuto = 0;
this.aumentarRevolucoes = function() {
this.revolucoesPorMinuto += 100;
}
}
//...
$(document).ready(function() {
var carro = new Carro();
$("#botaoAcelerar").click(function() {
carro.motor.aumentarRevolucoes();
});
});
E então, modificamos o código que usa jQuery para chamar o método acelerar() do Carro, em vez de chamar diretamente o método aumentarRevolucoes() do Motor:
$(document).ready(function() {
var carro = new Carro();
$("#botaoAcelerar").click(function() {
carro.acelerar();
});
});
Agora, o objeto Carro não precisa mais saber sobre a estrutura interna do objeto Motor. Isso torna o código mais fácil de entender e manter, e mais resistente a mudanças no design dos objetos.
Agora um exemplo mais completo:
/**
* ### Carro fora da lei ####
* Neste exemplo, a classe Carro está violando a Lei de Demeter ao chamar diretamente
* o método injetar() do BicoInjetor através do Motor e do Pistao.
* De acordo com a Lei de Demeter, um objeto só deve se comunicar com seus vizinhos
* imediatos, então Carro só deve se comunicar com Motor, e não com Pistao ou
* BicoInjetor.
*/
class BicoInjetor {
injetar() {
// Injeta combustível
let i=0
while(i<5) {
console.log("Tome gas!\n");
i++;
}
console.log("Vrummmmmm!\n");
}
}
class Pistao {
constructor() {
this.bicoInjetor = new BicoInjetor();
}
mover() {
// Move o pistão
this.bicoInjetor.injetar();
}
}
class Motor {
constructor() {
this.pistao = new Pistao();
}
iniciar() {
// Inicia o motor
this.pistao.mover();
}
}
class Carro {
constructor() {
this.motor = new Motor();
}
ligar() {
// Ligar o carro
this.motor.pistao.bicoInjetor.injetar(); // Violação da Lei de Demeter
}
}
let carro=new Carro();
carro.ligar();
console.log("Parado na Blitz do Demeter");
Refatorado:
/**
* ### Carro Legal ####
* Nesta versão refatorada, a classe Carro agora apenas se comunica com
* a classe Motor, que é seu vizinho imediato. Isso adere à Lei de Demeter, pois
* Carro não tem mais conhecimento dos detalhes internos de Pistao ou BicoInjetor.
*/
class BicoInjetor {
injetar() {
// Injeta combustível
let i=0
while(i<5) {
console.log("Tome gas!\n");
i++;
}
console.log("Vrummmmmm!\n");
}
}
class Pistao {
constructor() {
this.bicoInjetor = new BicoInjetor();
}
mover() {
// Move o pistão
this.bicoInjetor.injetar();
}
}
class Motor {
constructor() {
this.pistao = new Pistao();
}
iniciar() {
// Inicia o motor
this.pistao.mover();
}
}
class Carro {
constructor() {
this.motor = new Motor();
}
ligar() {
// Ligar o carro
this.motor.iniciar(); // Adere à Lei de Demeter
}
}
let carro=new Carro()
carro.ligar()
A Lei de Demeter é frequentemente infringida quando os desenvolvedores não percebem que estão expondo muitos detalhes de um objeto para outro. Isso pode acontecer em várias situações. Aqui estão alguns exemplos:
document.getElementById('meuId').style.color = 'red';
Neste caso, estamos acessando a propriedade style do elemento DOM retornado por getElementById('meuId') e então alterando a propriedade color desse objeto style. Isso é uma violação da Lei de Demeter, pois estamos navegando através de vários níveis de objetos.
let database = firebase.database();
let ref = database.ref('meusDados');
Neste exemplo, estamos acessando a database de firebase e então acessando a referência a 'meusDados' dessa database. Novamente, isso é uma violação da Lei de Demeter, pois estamos navegando através de vários níveis de objetos.
let valor = objeto.propriedade1.propriedade2.propriedade3;
Neste caso, estamos acessando propriedade1 de objeto, depois propriedade2 de propriedade1, e finalmente propriedade3 de propriedade2. Essa cadeia de acessos é uma violação clara da Lei de Demeter.
Embora seja tentador usar esses atalhos e eles possam tornar o código mais conciso, eles também podem tornar o código mais difícil de entender e manter. Aderir à Lei de Demeter pode resultar em código mais robusto e modularizado.