Classes (Código Limpo: Que Bruxaria é Essa?!?! - Parte 5)
Tags: cleancode, javascript
Published: 2021-10-01 13:53:49

## Prefira as classes do ES2015/ES6 às funções simples

É bem difícil obter herança de classes fácil de ler, construção e definições de métodos para funções clássicas do ES5. Se você precisa da herança (e fique atento porque talvez não precise), priorize as classes do ES2015/ES6. Entretanto, prefira funções pequenas às classes até que você se encontre na necessidade de objetos maiores e mais complexos.

### Não é recomendável:

```javascript
const Animal = function(age) {
  if (!(this instanceof Animal)) {
    throw new Error("Instantiate Animal with `new`");
  }

  this.age = age;
};

Animal.prototype.move = function move() {};

const Mammal = function(age, furColor) {
  if (!(this instanceof Mammal)) {
    throw new Error("Instantiate Mammal with `new`");
  }

  Animal.call(this, age);
  this.furColor = furColor;
};

Mammal.prototype = Object.create(Animal.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.liveBirth = function liveBirth() {};

const Human = function(age, furColor, languageSpoken) {
  if (!(this instanceof Human)) {
    throw new Error("Instantiate Human with `new`");
  }

  Mammal.call(this, age, furColor);
  this.languageSpoken = languageSpoken;
};

Human.prototype = Object.create(Mammal.prototype);
Human.prototype.constructor = Human;
Human.prototype.speak = function speak() {};
```

### É recomendável:

```javascript
class Animal {
  constructor(age) {
    this.age = age;
  }

  move() {
    /* ... */
  }
}

class Mammal extends Animal {
  constructor(age, furColor) {
    super(age);
    this.furColor = furColor;
  }

  liveBirth() {
    /* ... */
  }
}

class Human extends Mammal {
  constructor(age, furColor, languageSpoken) {
    super(age, furColor);
    this.languageSpoken = languageSpoken;
  }

  speak() {
    /* ... */
  }
}
```

## Use cadeias de métodos

Esse padrão é bem útil no JavaScript e você o encontra em várias bibliotecas como jQuery e Lodash. Permite que seu código seja expressivo e menos verboso. Por essa razão, eu digo, utilize cadeias de métodos e veja como seu código ficará limpo. Nas suas funções de classes, simplesmente retorne "this" no fim de cada função e você pode encadear métodos de classes mais distantes nela.

### Não é recomendável:

```javascript
class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  setMake(make) {
    this.make = make;
  }

  setModel(model) {
    this.model = model;
  }

  setColor(color) {
    this.color = color;
  }

  save() {
    console.log(this.make, this.model, this.color);
  }
}

const car = new Car("Ford", "F-150", "red");
car.setColor("pink");
car.save();
```

### É recomendável:

```javascript
class Car {
  constructor(make, model, color) {
    this.make = make;
    this.model = model;
    this.color = color;
  }

  setMake(make) {
    this.make = make;
    // NOTE: Returning this for chaining
    return this;
  }

  setModel(model) {
    this.model = model;
    // NOTE: Returning this for chaining
    return this;
  }

  setColor(color) {
    this.color = color;
    // NOTE: Returning this for chaining
    return this;
  }

  save() {
    console.log(this.make, this.model, this.color);
    // NOTE: Returning this for chaining
    return this;
  }
}

const car = new Car("Ford", "F-150", "red").setColor("pink").save();
```

## Prefira a composição à herança

De acordo com uma declaração notória em "Design Patterns", escrito pela "Gang of Four", você deve preferir a composição à herança sempre que puder. Há várias boas razões para usar a herança e existem várias boas razões para usar a composição. O ponto principal para essa máxima é que se sua mente, por instinto, pode ir na herança, tente pensar se a composição poderia moldar melhor o seu problema. Em alguns casos pode. Talvez você esteja se perguntando: "quando devo usar a herança?". Depende do seu problema que você tem nas mãos, porém temos uma lista decente de quando o uso da herança faz mais sentido que a composição:

* Sua herança representa uma relação "é - um" e não uma relação "tem - um" (Humano -> Animal vs. User -> UserDetails)
* Você pode reusar código das classes base (Humanos podem se mover como todos os animais)
* Você quer fazer alterações globais em classes derivadas ao mudar uma classe base (Mude o gasto calórico de todos os animais quando se movem)

### Não é recomendável:

```javascript
class Employee {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  // ...
}

// Bad because Employees "have" tax data. EmployeeTaxData is not a type of Employee
class EmployeeTaxData extends Employee {
  constructor(ssn, salary) {
    super();
    this.ssn = ssn;
    this.salary = salary;
  }

  // ...
}
```

### É recomendável:

```javascript
class EmployeeTaxData {
  constructor(ssn, salary) {
    this.ssn = ssn;
    this.salary = salary;
  }

  // ...
}

class Employee {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  setTaxData(ssn, salary) {
    this.taxData = new EmployeeTaxData(ssn, salary);
  }
  // ...
}
```

E aí? Gostaram? Até a próxima tradução! 🤗