ファクトリメソッド
CoddyのRubyジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 15/57。
ファクトリメソッドは、インスタンスを作成して返すクラスメソッドです。オブジェクトを作成する方法の1つに名前を付けます。クラスメソッド内では、newはself.newを意味します。
class Temperature
attr_reader :celsius
def initialize(celsius)
@celsius = celsius
end
def self.from_fahrenheit(f)
new((f - 32) * 5 / 9.0)
end
def self.freezing
new(0)
end
end
puts Temperature.from_fahrenheit(212).celsius
puts Temperature.freezing.celsius出力:
100.0
0テキストをオブジェクトに変換するのは、ファクトリーの一般的な役割です。解析処理はクラスの隣に置き、initializeはシンプルなままにします。
class Duration
attr_reader :seconds
def initialize(seconds)
@seconds = seconds
end
def self.parse(text)
new(text.split(":").map(&:to_i).reduce(0) { |acc, part| acc * 60 + part })
end
end
puts Duration.parse("1:30").seconds
puts Duration.parse("2:00:05").seconds出力:
90
7205ファクトリーは不正な入力を拒否できます。nilを返すと、呼び出し元はifを使って結果を確認できます。エラーを発生させると、呼び出し元が rescue しない限りプログラムは停止します。
class Color
attr_reader :hex
def initialize(hex)
@hex = hex
end
def self.parse(text)
return nil unless text.match?(/\A#[0-9a-f]{6}\z/i)
new(text.downcase)
end
end
["#FF8800", "orange"].each do |text|
color = Color.parse(text)
puts color ? "ok #{color.hex}" : "not a color: #{text}"
end出力:
ok #ff8800
not a color: orangeprivate_class_method :new によって、new はクラス内からのみ呼び出せるようになるため、オブジェクトを作成する唯一の方法はファクトリになります。
class Money
attr_reader :cents
def initialize(cents)
@cents = cents
end
private_class_method :new
def self.from_cents(cents)
new(cents)
end
end
puts Money.from_cents(250).cents
begin
Money.new(250)
rescue NoMethodError => e
puts e.message
end出力:
250
private method `new' called for class Moneyチャレンジ
簡単Durationクラスを完成させてください。initialize(seconds)は秒数を保存します。ファクトリメソッドDuration.parse(text)はm:ssまたはh:mm:ssを読み込み、ファクトリメソッドDuration.from_minutes(m)は整数の分数を受け取り、plus(other)は合計を持つ新しいDurationを返し、to_sは分と秒を2桁で表したh:mm:ssを返します。
提供されたコードは時間の長さを読み込みます。45mのような行はfrom_minutesを通り、それ以外はparseを通ります。各時間の長さを出力し、最後にtotal 1:47:10を出力します。
コードはduration.rbに記述してください。main.rbには提供された入力/出力コードが含まれており、編集できません。
自分で試してみよう
require_relative 'duration'
# 提供された入出力コード: そのままにしてください
input = []
while (line = gets)
input << line.chomp
end
durations = input.map do |line|
line.end_with?("m") ? Duration.from_minutes(line.to_i) : Duration.parse(line)
end
durations.each { |d| puts d }
puts "total #{durations.reduce(Duration.new(0)) { |sum, d| sum.plus(d) }}"
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rubyオンラインコンパイラ