Skip to content

Instantly share code, notes, and snippets.

@gpupo
Last active June 8, 2023 22:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gpupo/6385b8d4e27b6fb5a8bf919f44bce296 to your computer and use it in GitHub Desktop.
Save gpupo/6385b8d4e27b6fb5a8bf919f44bce296 to your computer and use it in GitHub Desktop.
A Lei de Demeter, princípio do mínimo conhecimento

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()

Exemplos de infrações no dia a dia

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:

Manipulação de DOM em JavaScript:

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.

Uso de bibliotecas e frameworks:

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.

Manipulação de objetos complexos

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment