תבנית Factory
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Swift של Coddy. שיעור 43 מתוך 57.
תבנית factory מרכזת את יצירת האובייקטים במקום אחד. הקוראים מבקשים את מה שהם צריכים, לרוב לפי שם או סוג, ומקבלים אובייקט מוכן, בלי לדעת איזה סוג קונקרטי נוצר:
protocol Shape { func area() -> Double }
struct Square: Shape { let side: Double; func area() -> Double { side * side } }
struct Circle: Shape { let r: Double; func area() -> Double { 3 * r * r } }
enum ShapeFactory {
static func make(_ kind: String, size: Double) -> (any Shape)? {
switch kind {
case "square": return Square(side: size)
case "circle": return Circle(r: size)
default: return nil
}
}
}
print(ShapeFactory.make("square", size: 3)!.area())
print(ShapeFactory.make("hexagon", size: 3) == nil)פלט:
9.0
trueהקורא תלוי בפרוטוקול בלבד. הוספת צורה חדשה פירושה שינוי המפעל, ולא כל מקום שיוצר צורות:
protocol Notifier { func send(_ m: String) -> String }
struct Email: Notifier { func send(_ m: String) -> String { "email: \(m)" } }
struct SMS: Notifier { func send(_ m: String) -> String { "sms: \(m)" } }
func makeNotifier(for user: String) -> any Notifier {
user.hasSuffix("@mail.com") ? Email() : SMS()
}
print(makeNotifier(for: "ada@mail.com").send("hi"))
print(makeNotifier(for: "555-0100").send("hi"))פלט:
email: hi
sms: hiמתודות מפעל סטטיות על הטיפוס עצמו הן צורה קלה יותר של התבנית. הן מעניקות שמות לדרכים נפוצות ליצירת ערך:
struct Color {
let r: Int, g: Int, b: Int
static func gray(_ v: Int) -> Color { Color(r: v, g: v, b: v) }
static let white = Color(r: 255, g: 255, b: 255)
}
print(Color.gray(100).g)
print(Color.white.b)פלט:
100
255enum ללא מקרים, כמו ShapeFactory, הוא דרך נפוצה לקבץ פונקציות factory: אי אפשר ליצור ממנו מופע, ולכן הוא משמש אך ורק כמרחב שמות.
enum ShapeFactory { // אין מקרים: לא ניתן ליצור מופע
static func make(_ kind: String, size: Double) -> (any Shape)? { ... }
}אתגר
קלכתבו מפעל לתוכניות תמחור. לפרוטוקול Plan יש name ו-price(forUsers:) -> Int. ממשו את Free (0, ועד 3 משתמשים בלבד: מעל לכך המחיר הוא -1, כלומר השימוש אינו מורשה), את Team (10 למשתמש) ואת Enterprise (תשלום קבוע של 500 ועוד 5 לכל משתמש מעל 100). השלימו את PlanFactory.make(_:), שמחזירה את התוכנית עבור free, team או enterprise, ואת nil אחרת.
הקוד שסופק קורא שורות בפורמט plan,users ומדפיס team for 12 users: 120, free does not allow 5 users או unknown plan: gold.
הקוד שלכם צריך להיכתב בקבצים Plan.swift, Free.swift, Team.swift, Enterprise.swift ו-PlanFactory.swift. הקובץ main.swift מכיל את קוד הקלט/פלט שסופק, ואי אפשר לערוך אותו.
נסו בעצמכם
// קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
let p = line.split(separator: ",").map(String.init)
let users = Int(p[1])!
guard let plan = PlanFactory.make(p[0]) else {
print("unknown plan: \(p[0])")
continue
}
let price = plan.price(forUsers: users)
print(price < 0 ? "\(plan.name) does not allow \(users) users" : "\(plan.name) for \(users) users: \(price)")
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
תרגלו בעצמכם: Swift אונליין