תבנית Factory
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 43 מתוך 57.
תבנית factory מרכזת את יצירת האובייקטים במקום אחד. מי שקוראים לה מבקשים את מה שהם צריכים, לעיתים קרובות לפי שם, ומקבלים אובייקט מוכן בלי לדעת איזו מחלקה נוצרה:
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פלט:
9
nilמיפוי גיבוב משמות למחלקות הופך את המפעל לקצר יותר וקל יותר להרחבה. מחלקות הן אובייקטים, ולכן אפשר לאחסן אותן במיפוי גיבוב ולשלוח להן 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פלט:
Meow
unknown animal: cowמפעל יכול גם לאפשר לקוד אחר לרשום סוגים חדשים בזמן ריצה, כך שהוספת סוג אינה מחייבת לערוך את המפעל:
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פלט:
zipping
["zip"]הקוראים תלויים רק במה שהאובייקטים יכולים לעשות, כאן area או speak, ולעולם לא במחלקות הקונקרטיות. צורה חדשה פירושה מחלקה חדשה אחת ורשומה חדשה אחת במפעל, וללא שינוי בשום מקום אחר:
shape = ShapeFactory.create(kind, size) # Square, Circle, ...
puts shape.area # הקוד הקורא לעולם אינו מציין שם של מחלקהאתגר
קלהשלימו את הצורות ואת ShapeFactory.create(kind, size). Square, Circle ו-Triangle (שווה־צלעות) יורשות ממחלקת הבסיס Shape, שהמתודה to_s שלה מחזירה square 3: area 9.00, עם שם המחלקה באותיות קטנות, הגודל והשטח בשתי ספרות אחרי הנקודה העשרונית. השתמשו ב-3.14159 עבור פאי וב-Math.sqrt(3) / 4 * size**2 עבור המשולש. המפעל מחפש את סוג הצורה בקבוע מסוג גיבוב קפוא בשם KINDS ומחזיר nil עבור סוג צורה לא מוכר.
הקוד שסופק קורא שורות square 3, מבקש מהמפעל ליצור צורה עבור כל שורה ומדפיס אותה, או unknown shape: hexagon.
הקוד שלכם ייכתב בקבצים shape.rb, square.rb, circle.rb, triangle.rb ו-shape_factory.rb. הקובץ main.rb מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
require_relative 'shape'
require_relative 'square'
require_relative 'circle'
require_relative 'triangle'
require_relative 'shape_factory'
# קוד קלט/פלט שסופק: יש להשאיר אותו כפי שהוא
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
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין