SOLID

5 principes de POO

Les principes

  1. Single Responsibility Principle
  2. Open/Closed Principle
  3. Liskov Substitution Principle
  4. Interface Segregation Principle
  5. Dependency Inversion Principle

Single Responsibility Principle

Un module doit avoir une seule responsabilité. Une seule raison de changer.

class User {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  getFullName() {
    return `<h1>Fullname: ${this.firstName} ${this.lastName}</h1>`;
  }
}

Single Responsibility Principle

Un module doit avoir une seule responsabilité. Une seule raison de changer.

class User {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  getFullName() {
    return this.firstName + " " + this.lastName;
  }
}

function displayFullName(fullName) {
  return `<h1>Fullname: ${fullName}</h1>`;
}

const user = new User("Toby", "Fox");
displayFullName(user.fullName());

Open/Closed Principle

Un module doit être ouvert aux extensions,

mais fermé aux modifications.

 

Possibilité d'étendre sans devoir modifier

Open/Closed Principle

class Square {
  constructor(size) {
    this.type = "square";
    this.size = size;
  }
}

class Circle {
  constructor(radius) {
    this.type = "circle";
    this.radius;
  }
}

function sumAreas(shapes) {
  const areas = shapes.map(shape => {
    switch (shape.type) {
      case "circle":
        return shape.radius * shape.radius * Math.PI;
      case "square":
        return shape.size * shape.size;
      default:
        throw new Error("Unknown shape");
    }
  });

  return areas.reduce((sum, area) => sum + area, 0);
}

Open/Closed Principle

class Square {
  constructor(size) {
    this.type = "square";
    this.size = size;
  }

  area() {
    return this.size * this.size;
  }
}

class Circle {
  constructor(radius) {
    this.type = "circle";
    this.radius;
  }

  area() {
    return this.radius * this.radius * Math.PI;
  }
}

function sumAreas(shapes) {
  const areas = shapes.map(shape => shape.area());
  return areas.reduce((sum, area) => sum + area, 0);
}

Liskov Substitution Principle

(sympa le nom...)

Si deux classes réalise la même interface, on peut utiliser l'une ou l'autre sans casser le programme.

 

Si ça casse, alors elles ne devraient pas partager la même interface.

L'abstraction est incorrecte

Liskov Substitution Principle

class Rectangle {
  setHeight(height) {
    this.height = height;
  }
  setWidth(width) {
    this.width = width;
  }
}

class Square extends Rectangle {
  setHeight(height) {
    // Uh oh... :S
    // Que faire ?
  }
}

Interface Segregation Principle

// Interface pour des formes géométrique,
// imposée par une librairie
interface Shape {
    area()
    volume()
}

class Square {
   area() {
       this.size * this.size;
   }

   // En trop généralisant, on force le client 
   // à faire des choses incorrectes
   volume() {
       // ? throw error ?
   }
}

Ne pas forcer le code client à implémenter une interface dont il n'a pas usage.

 

Dependency Inversion Principle

Les modules de haut niveau ne doivent pas dépendre des détails des modules de bas niveau.

 

Ils doivent dépendre d'abstractions que les modules de bas-niveau doivent satisfaire

Dependency Inversion Principle

// Déplace la voiture un peu en avant
function avancerUnPeu(voiture) {
  voiture.tourneClef();
  voiture.enleveFreinAMain();
  voiture.appuieAccelerateur();
  voiture.freine();
  voiture.metFreinAMain();
  voiture.tourneClef();
}

Dependency Inversion Principle

class VehiculeVoiture {
  constructor(voiture) {
    this.voiture = voiture;
  }

  allumer() {
    this.voiture.tourneClef();
    this.voiture.enleveFreinAMain();
  }

  avancer() {
    this.voiture.appuieAccelerateur();
  }

  arreter() {
    this.voiture.freine();
  }

  eteindre() {
    this.voiture.metFreinAMain();
    this.voiture.tourneClef();
  }
}
// Déplace un véhicule un peu en avant
function avancerUnPeu(vehicule) {
  vehicule.allumer();
  vehicule.avancer();
  vehicule.arreter();
  vehicule.eteindre();
}

const vehicule = new VehiculeVoiture(voiture);
avancerUnPeu(vehicule);
Made with Slides.com