動画概要
以下の動画で、SOLID原則の一つであるOCP(Open Closed Principle・開放/閉鎖原則)について、FizzBuzz問題を通じて解説しました。
ソフトウェアの拡張に対して開かれている一方で、修正に対しては閉じているという原則です。
内容
元々のFizzBuzz
通常、FizzBuzzは以下のような形で実装されますが、新しいルールの追加が求められた場合、このコードでは変更が必要になります。
コード
main.rb
class FizzBuzz
def convert(number)
return 'FizzBuzz' if (number % 15).zero?
return 'Buzz' if (number % 5).zero?
return 'Fizz' if (number % 3).zero?
number.to_s
end
end
実行例
main.rb
require_relative './fizz_buzz'
fizz_buzz = FizzBuzz.new
(1..30).each do |number|
puts fizz_buzz.convert(number)
end
FizzBuzzの拡張
新たなルール、「2の倍数で"Nizz"を返す」を追加するとなったとき、既存のconvertメソッドに修正を加える必要があります。これはOCPに違反します。
NewFizzBuzzの実装
動的にルールを適用できるNewFizzBuzzクラスを導入することで、この問題を解決しました。
rulesモジュール
rule.rb
module Rules
class Rule
def initialize(divisor, word)
@divisor = divisor
@word = word
end
def match(_carry, number)
(number % @divisor).zero?
end
def apply(carry, _number)
carry + @word
end
end
class DefaultRule
def match(carry, _number)
carry.empty?
end
def apply(_carry, number)
number.to_s
end
end
end
new_fizz_buzzクラス
new_fizz_buzz.rb
class NewFizzBuzz
def initialize(rules)
@rules = rules
end
def convert(number)
carry = ''
@rules.each do |rule|
carry = rule.apply(carry, number) if rule.match(carry, number)
end
carry
end
end
実行例
main.rb
require_relative './new_fizz_buzz'
require_relative './rules'
rules = [
Rules::Rule.new(2, 'Nizz'),
Rules::Rule.new(3, 'Fizz'),
Rules::Rule.new(5, 'Buzz'),
Rules::DefaultRule.new
]
new_fizz_buzz = NewFizzBuzz.new(rules)
(1..30).each do |number|
puts new_fizz_buzz.convert(number)
end
この新しいアプローチにより、コードの拡張がしやすくなります。