Mẫu Factory
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 43 trên 57.
Mẫu factory tập trung việc tạo đối tượng ở một nơi. Bên gọi yêu cầu đối tượng cần dùng, thường bằng tên, rồi nhận về một đối tượng sẵn sàng mà không cần biết lớp nào đã được tạo:
class Square
def initialize(side)
@side = side
end
def area
@side * @side
end
end
class Circle
def initialize(r)
@r = r
end
def area
(3.14159 * @r * @r).round(2)
end
end
class ShapeFactory
def self.create(kind, size)
case kind
when "square" then Square.new(size)
when "circle" then Circle.new(size)
end
end
end
puts ShapeFactory.create("square", 3).area
puts ShapeFactory.create("hexagon", 3).inspectĐầu ra:
9
nilMột hash ánh xạ tên đến lớp giúp factory ngắn gọn hơn và dễ mở rộng hơn. Lớp là các đối tượng, vì vậy bạn có thể lưu chúng trong một hash rồi gửi new:
class Dog
def speak
"Woof"
end
end
class Cat
def speak
"Meow"
end
end
class AnimalFactory
KINDS = { "dog" => Dog, "cat" => Cat }.freeze
def self.create(kind)
klass = KINDS.fetch(kind) { raise ArgumentError, "unknown animal: #{kind}" }
klass.new
end
end
puts AnimalFactory.create("cat").speak
begin
AnimalFactory.create("cow")
rescue ArgumentError => e
puts e.message
endĐầu ra:
Meow
unknown animal: cowMột factory cũng có thể cho phép đoạn code khác đăng ký các loại mới khi chương trình đang chạy, vì vậy việc thêm một loại không đồng nghĩa với việc chỉnh sửa factory:
class Plugins
@kinds = {}
class << self
def register(name, klass)
@kinds[name] = klass
end
def build(name)
@kinds.fetch(name).new
end
def names
@kinds.keys.sort
end
end
end
class Zip
def run
"zipping"
end
end
Plugins.register("zip", Zip)
puts Plugins.build("zip").run
p Plugins.namesĐầu ra:
zipping
["zip"]Các bên gọi chỉ phụ thuộc vào những gì đối tượng có thể làm, ở đây là area hoặc speak, chứ không phụ thuộc vào các lớp cụ thể. Một hình dạng mới chỉ cần một lớp mới và một mục mới trong factory, không cần thay đổi ở bất kỳ nơi nào khác:
shape = ShapeFactory.create(kind, size) # Square, Circle, ...
puts shape.area # Bên gọi không cần nêu tên lớp (class)Thử thách
DễHoàn thiện các hình và ShapeFactory.create(kind, size). Square, Circle và Triangle (tam giác đều) dùng chung lớp cơ sở Shape, trong đó to_s trả về square 3: area 9.00, gồm tên lớp viết thường, kích thước và diện tích với hai chữ số thập phân. Dùng 3.14159 cho pi và Math.sqrt(3) / 4 * size**2 cho tam giác. Factory tra cứu loại hình trong hằng số hash đóng băng KINDS và trả về nil nếu không tìm thấy loại hình.
Code được cung cấp đọc các dòng square 3, yêu cầu factory tạo từng hình rồi in ra, hoặc unknown shape: hexagon.
Code của bạn nằm trong các tệp shape.rb, square.rb, circle.rb, triangle.rb và shape_factory.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
require_relative 'shape'
require_relative 'square'
require_relative 'circle'
require_relative 'triangle'
require_relative 'shape_factory'
# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
input = []
while (line = gets)
input << line.chomp
end
input.each do |line|
kind, size = line.split
shape = ShapeFactory.create(kind, size.to_f)
puts shape || "unknown shape: #{kind}"
end
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
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpBiến instancePhương thức và selfto_s và inspectÔn tập: thẻ thư viện4Tính đóng gói
Phương thức riêng tưPhương thức được bảo vệPhương thức thiết lập riêng tưBảo vệ trạng tháiÔn tập: máy bán hàng tự động7Tính đa hình và duck typing
Tính đa hìnhDuck typingPhương thức trừu tượngcase và lớpÔn tập: phương thức thanh toán2Phương thức truy cập và self
Phương thức đọc và ghiPhương thức gán tùy chỉnhself trong phương thứcĐịnh danh và tính bằng nhauÔn tập: Danh sách liên hệTự luyện tập: Trình biên dịch Ruby online