SOLID : Open/Closed Principle (OCP)

code 9 juil. 2025

Objectif : Une classe peut-être ouverte pour l'ajout ou l'extension mais fermée pour la modification

On peut y ajouter des fonctionnalités mais doit éviter la surcharge et la modification de code existant.

Remarque : En Ruby, la possibilité de sucharge se fait aussi bien via l'héritage que par le mixin ou l'inclusion, donc il s'agit d'une vigilence spécifique

Anti-pattern

class PushManager 
  def initialize(medium: "email")
  end
  def send(content: )
    if medium == "email"
      # send by email
    elsif medium == "sms"
      # send by sms
    else 
      raise "Medium unavailable"
    end
  end
end

🔴 Problème : Chaque fois qu'on veut ajouter un nouveau medium il faut modifier la Classe PushManager

🔴 Autre problème : l'usage d'une structure de controle dans ce cas n'est pas souhaitable, une map/hashage serait plus adaptée

Rubyway : l'usage de String et non de Symbol pour identifier le medium n'est pas optimum, une String n'est pas unique, un Symbol si.

Pattern

class Pusher 
  def initialize(content:)
    @content = content
  end
  def send 
  raise NotImplementedError, "Must be implemented in a subclass"
end

class EmailPusher < Pusher

  def send
    # send by mail
  end
end

class SMSPusher < Pusher

  def send
    # send by SMS
  end
end

class PushManager
  def self.send(content:, medium: EmailPusher)
    medium::new(content: content).send
  end

end

# usage 
data = "......"
PushManager.send content: data, medium: SMSPusher
Maintenant on peut instancier un nouveau type de Pusher sans modifier le PushManager
Remarque : on ne juge pas de la qualité d'un code à sa concision
Remarque : la méthode ::send de PushManager est une méthode de classe

Mots clés

Romain GEORGES

Open Source evangelist & Ruby enthousiast