Menu
CoddyTech

Phương thức tạo đối tượng

Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 15 trên 57.

Phương thức tạo đối tượng (factory method) là một phương thức của lớp, tạo và trả về một instance. Nó đặt tên cho một cách tạo đối tượng. Bên trong phương thức của lớp, new có nghĩa là 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

Đầu ra:

100.0
0

Chuyển văn bản thành đối tượng là công việc phổ biến của một lớp nhà máy. Phần phân tích nằm cạnh lớp, còn initialize vẫn đơn giản:

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

Đầu ra:

90
7205

Một factory có thể từ chối đầu vào không hợp lệ. Trả về nil cho phép bên gọi kiểm tra kết quả bằng if; phát sinh lỗi sẽ dừng chương trình trừ khi bên gọi bắt lỗi:

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

Đầu ra:

ok #ff8800
not a color: orange

private_class_method :new khiến bạn chỉ có thể gọi new bên trong lớp, vì vậy các hàm tạo trở thành cách duy nhất để tạo đối tượng:

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

Đầu ra:

250
private method `new' called for class Money
challenge icon

Thử thách

Dễ

Hoàn thiện lớp Duration. initialize(seconds) lưu số giây. Hàm tạo Duration.parse(text) đọc định dạng m:ss hoặc h:mm:ss, hàm tạo Duration.from_minutes(m) nhận số phút nguyên, plus(other) trả về một Duration mới có tổng thời lượng, còn to_s trả về định dạng h:mm:ss với phút và giây gồm hai chữ số.

Code được cung cấp đọc các khoảng thời lượng: những dòng như 45m được xử lý bằng from_minutes, các dòng còn lại được xử lý bằng parse. Code in ra từng khoảng thời lượng, rồi in ra total 1:47:10.

Hãy viết code trong duration.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.

Tự làm thử

require_relative 'duration'

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
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) }}"
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Ruby online