Mẫu Strategy
Thuộc phần Lập trình hướng đối tượng trong hành trình Swift của Coddy. Bài học 45 trên 57.
Mẫu strategy đặt từng biến thể của thuật toán trong kiểu riêng, đằng sau một giao thức dùng chung. Đoạn code sử dụng mẫu này sẽ giữ một strategy và có thể thay đổi strategy đó khi chạy:
protocol ShippingStrategy {
func cost(weight: Int) -> Int
}
struct Standard: ShippingStrategy { func cost(weight: Int) -> Int { 5 + weight } }
struct Express: ShippingStrategy { func cost(weight: Int) -> Int { 15 + weight * 2 } }
struct Checkout {
var shipping: any ShippingStrategy
func total(price: Int, weight: Int) -> Int { price + shipping.cost(weight: weight) }
}
var c = Checkout(shipping: Standard())
print(c.total(price: 100, weight: 3))
c.shipping = Express()
print(c.total(price: 100, weight: 3))Đầu ra:
108
121Trong Swift, closure thường là đủ cho một chiến lược chỉ có một phương thức. Kiểu này lưu trữ một hàm và gọi hàm đó:
struct Sorter {
var rule: (String, String) -> Bool
func sort(_ words: [String]) -> [String] { words.sorted(by: rule) }
}
let words = ["banana", "kiwi", "apple"]
var s = Sorter(rule: <)
print(s.sort(words))
s.rule = { $0.count < $1.count }
print(s.sort(words))Đầu ra:
["apple", "banana", "kiwi"]
["kiwi", "apple", "banana"]Chiến lược thay thế switch bên trong thuật toán. Các biến thể mới là các kiểu mới (hoặc closure), còn code sử dụng chúng vẫn giữ nguyên:
// Không có chiến lược: mỗi tùy chọn mới đều khiến bạn phải sửa hàm (function) này
func cost(kind: String, weight: Int) -> Int {
switch kind { case "standard": return 5 + weight; default: return 15 + weight * 2 }
}
// Có chiến lược: Checkout không bao giờ thay đổi
struct Overnight: ShippingStrategy { func cost(weight: Int) -> Int { 40 } }Có thể chọn chiến lược dựa trên dữ liệu, chẳng hạn như từ cài đặt của người dùng, bằng một factory nhỏ:
protocol Discount { func apply(_ price: Int) -> Int }
struct NoDiscount: Discount { func apply(_ p: Int) -> Int { p } }
struct Percent: Discount { let rate: Int; func apply(_ p: Int) -> Int { p - p * rate / 100 } }
func discount(for member: String) -> any Discount {
member == "gold" ? Percent(rate: 20) : NoDiscount()
}
print(discount(for: "gold").apply(200))
print(discount(for: "basic").apply(200))Đầu ra:
160
200Thử thách
DễĐòn tấn công của nhân vật trong trò chơi là một chiến lược. Giao thức Attack có name và damage(strength:) -> Int. Hãy triển khai Sword (strength * 2), Bow (strength + 5) và Magic (lưu mana; sát thương bằng strength * 3 khi mana ít nhất là 10, và bằng 1 trong các trường hợp khác; bản thân damage không thay đổi mana). Hero lưu strength và attack, còn strike() trả về Ada hits with sword for 20.
Code được cung cấp đọc tên và sức mạnh của anh hùng, sau đó đọc các lệnh equip sword, equip bow, equip magic 15 hoặc strike. Code in ra kết quả của mỗi đòn tấn công.
Hãy viết code trong các tệp Attack.swift, Sword.swift, Bow.swift, Magic.swift và Hero.swift. main.swift chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.
Tự làm thử
// Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
var input: [String] = []
while let line = readLine() { input.append(line) }
let head = input[0].split(separator: ",").map(String.init)
var hero = Hero(name: head[0], strength: Int(head[1])!, attack: Sword())
for cmd in input.dropFirst() {
let p = cmd.split(separator: " ").map(String.init)
if p[0] == "strike" { print(hero.strike()); continue }
switch p[1] {
case "bow": hero.attack = Bow()
case "magic": hero.attack = Magic(mana: Int(p[2])!)
default: hero.attack = Sword()
}
}
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ớpPhương thức và selfHàm khởi tạoLớp là tham chiếuÔn tập: Thẻ thư viện2Struct và kiểu giá trị
StructNgữ nghĩa giá trịPhương thức thay đổiStruct hay classÔn tập: mặt hàng trong kho5Kế thừa
Lớp conGhi đè phương thứcHàm khởi tạo và superfinal và hệ phân cấpÔn tập: hệ phân cấp nhân viên8Các giao thức tiêu chuẩn
CustomStringConvertibleEquatableComparableHashableÔn tập: Sắp xếp tùy chỉnhTự luyện tập: Playground Swift