Here’s how the SOLID principles can be implemented using Ruby:
- Violation:
class User def initialize(name, email) @name = name @mail = email end def send_email(message) # Code to send email puts "Sending email to #{@mail}: #{message}" end end
- Solution: Separate responsibilities into different classes:
class User attr_reader :name, :email def initialize(name, email) @name = name @mail = email end end class EmailService def send_email(user, message) # Code to send email puts "Sending email to #{user.email}: #{message}" end end
- Violation:
class Discount def apply_discount(product, discount_type) if discount_type == :percentage product.price * 0.9 elsif discount_type == :fixed product.price - 10 end end end
- Solution: Extend functionality without modifying existing code:
class Discount def apply_discount(product) raise NotImplementedError, 'Subclasses must implement the apply_discount method' end end class PercentageDiscount < Discount def apply_discount(product) product.price * 0.9 end end class FixedDiscount < Discount def apply_discount(product) product.price - 10 end end
- Violation:
class Bird def fly 'Flying...' end end class Penguin < Bird def fly raise 'Penguins can’t fly!' end end
- Solution: Ensure subclasses can replace the base class without breaking behavior:
class Bird def move 'Moving...' end end class Penguin < Bird def move 'Swimming...' end end
- Violation:
class Worker def work raise NotImplementedError end def eat raise NotImplementedError end end class HumanWorker < Worker def work puts 'Human working' end def eat puts 'Human eating' end end class RobotWorker < Worker def work puts 'Robot working' end def eat raise 'Robots don’t eat!' end end
- Solution: Split interfaces based on specific needs:
module Workable def work raise NotImplementedError end end module Eatable def eat raise NotImplementedError end end class HumanWorker include Workable include Eatable def work puts 'Human working' end def eat puts 'Human eating' end end class RobotWorker include Workable def work puts 'Robot working' end end
- Violation:
class LightBulb def turn_on puts 'LightBulb is on' end end class Switch def initialize(bulb) @bulb = bulb end def operate @bulb.turn_on end end
- Solution: Depend on abstractions, not concrete classes:
module Switchable def turn_on raise NotImplementedError end end class LightBulb include Switchable def turn_on puts 'LightBulb is on' end end class Switch def initialize(device) @device = device end def operate @device.turn_on end end
These Ruby examples illustrate how adhering to SOLID principles can help maintain clean, scalable, and modular code.