paint-brush
Herança versus composição: usando um RPG em JavaScript como exemplopor@kliukovkin
13,348 leituras
13,348 leituras

Herança versus composição: usando um RPG em JavaScript como exemplo

por Georgii Kliukovkin4m2022/12/21
Read on Terminal Reader

Muito longo; Para ler

Com a composição, você pode evitar problemas de herança e o javascript é uma linguagem perfeita para isso.
featured image - Herança versus composição: usando um RPG em JavaScript como exemplo
Georgii Kliukovkin HackerNoon profile picture

Problemas de Herança

  • Duplicação de código em crianças
  • Complexidade excessiva na hierarquia de herança
  • Mudar o comportamento dos pais pode levar a erros nos filhos


Neste artigo, veremos do que se tratam esses problemas e como podemos resolvê-los usando a composição.


o problema com as linguagens orientadas a objetos é que elas têm todo esse ambiente implícito que carregam consigo. Você queria uma banana, mas o que conseguiu foi um gorila segurando a banana e toda a selva. - Joe Armstrong, criador de Erlang

Herança de RPG

Considere o processo de criação de uma hierarquia de personagens de RPG. Inicialmente, são necessários dois tipos de personagens - Guerreiro e Mago, cada um com uma certa quantidade de saúde e um nome. Essas propriedades são públicas e podem ser movidas para a classe Character pai.

 class Character { constructor(name) { this.name = name; this.health = 100; } }


Um guerreiro pode atacar, gastando sua resistência:

 class Warrior extends Character { constructor(name) { super(name); this.stamina = 100; } fight() { console.log(`${this.name} takes a mighty swing!`); this.stamina--; } }


E um mago pode lançar feitiços que gastam uma certa quantidade de mana:

 class Mage extends Character { constructor(name) { super(name); this.mana = 100; } cast() { console.log(`${this.name} casts a fireball!`); this.mana--; } }

Problema de Classe Paladino

Agora, vamos apresentar uma nova classe, Paladino . Um Paladino pode lutar e lançar feitiços. Como podemos resolver isso? Aqui estão algumas soluções que compartilham a mesma falta de elegância:


  • Podemos fazer de Paladin um descendente de Character e implementar ambos os métodos fight() e cast() a partir do zero. Nesse caso, o princípio DRY é violado porque cada um dos métodos será duplicado na criação e precisará de sincronização constante com os métodos das classes Mage e Fighter para rastrear as alterações.


  • Os métodos fight() e cast() podem ser implementados no nível da classe Character para que todos os três tipos de personagem os tenham. Esta é uma solução um pouco melhor, mas neste caso, o desenvolvedor deve substituir o método fight() para o mago e o método cast() para o guerreiro, substituindo-os por métodos vazios ou consertando um erro.

Composição

Esses problemas podem ser resolvidos com uma abordagem funcional usando composição. Basta partir não de seus tipos, mas de suas funções. Basicamente, temos duas características principais que determinam as habilidades dos personagens - a habilidade de lutar e a habilidade de lançar feitiços.


Esses recursos podem ser definidos usando funções de fábrica que estendem o estado que define o caractere:

 const canCast = (state) => ({ cast: (spell) => { console.log(`${state.name} casts ${spell}!`); state.mana--; } }) const canFight = (state) => ({ fight: () => { console.log(`${state.name} slashes at the foe!`); state.stamina--; } })


Assim, um personagem é definido por um conjunto dessas habilidades e propriedades iniciais, tanto gerais (nome e saúde) quanto particulares (resistência e mana):

 const fighter = (name) => { let state = { name, health: 100, stamina: 100 } return Object.assign(state, canFight(state)); } const mage = (name) => { let state = { name, health: 100, mana: 100 } return Object.assign(state, canCast(state)); } const paladin = (name) => { let state = { name, health: 100, mana: 100, stamina: 100 } return Object.assign(state, canCast(state), canFight(state)); }

Conclusão

Com a composição, você pode evitar problemas de herança usando composição, e o javascript é a linguagem perfeita para fazer isso.