امتدادات البروتوكولات
جزء من قسم البرمجة كائنية التوجه في رحلة Swift على Coddy. الدرس 29 من 57.
يوفّر امتداد البروتوكول تطبيقًا افتراضيًا لأساليب البروتوكول. ويحصل عليه كل نوع متوافق مجانًا، ولا يزال بإمكان النوع توفير نسخته الخاصة:
protocol Greeter {
var name: String { get }
func greet() -> String
}
extension Greeter {
func greet() -> String { "Hello, \(name)!" }
}
struct English: Greeter { let name: String }
struct Pirate: Greeter {
let name: String
func greet() -> String { "Ahoy, \(name)!" }
}
print(English(name: "Ada").greet())
print(Pirate(name: "Ada").greet())الناتج:
Hello, Ada!
Ahoy, Ada!يمكن للامتداد أيضًا إضافة أساليب جديدة مبنية بالكامل على المتطلبات. يكتب النوع المطابق الجزء الصغير المطلوب ويحصل على الباقي:
protocol Scored {
var points: [Int] { get }
}
extension Scored {
var total: Int { points.reduce(0, +) }
var best: Int { points.max() ?? 0 }
func summary() -> String { "total \(total), best \(best)" }
}
struct Player: Scored {
let points: [Int]
}
print(Player(points: [3, 9, 4]).summary())الناتج:
total 16, best 9يتيح هذا مشاركة السلوك بين الهياكل والفئات والتعدادات دون استخدام الوراثة. تعمل المكتبة القياسية بالطريقة نفسها: تحصل كل Collection على isEmpty وfirst وmap من امتدادات البروتوكول.
extension Collection {
// isEmpty, first, map, filter, ... كلها معرّفة مرة واحدة هنا
// وكل array و set و dictionary و string يحصل عليها
}يضيف الامتداد المقيّد أساليبَ لبعض الأنواع المتوافقة فقط، ويُكتب باستخدام where:
protocol Container {
associatedtype Item
var items: [Item] { get }
}
extension Container where Item == Int {
var sum: Int { items.reduce(0, +) }
}
struct Box: Container {
var items: [Int]
}
print(Box(items: [2, 5]).sum)الناتج:
7التحدي
سهلأعلن عن بروتوكول Priced يتطلب var price: Int { get } (بالسنتات) وvar formatted: String { get }. في امتداد البروتوكول، امنح formatted قيمة افتراضية تُرجع $4.50، وأضف طريقة isAffordable(budget:) تُرجع ما إذا كان السعر يناسب الميزانية. اجعل البنيتين Coffee (بسعر 450) وSandwich (مع price مخزّن) متوافقتين مع البروتوكول. يجب أن تستبدل Coffee القيمة الافتراضية لـ formatted بـ coffee $4.50.
يقرأ الكود المتوفر ميزانية، ثم أسطرًا تحتوي على coffee أو sandwich,650. ويطبع formatted وyes أو no لكل عنصر.
ضع كودك في Priced.swift وCoffee.swift وSandwich.swift. يحتوي main.swift على كود الإدخال/الإخراج المتوفر، ولا يمكن تعديله.
جرّب بنفسك
// كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
var input: [String] = []
while let line = readLine() { input.append(line) }
let budget = Int(input[0])!
for line in input.dropFirst() {
let item: any Priced = line == "coffee" ? Coffee() : Sandwich(price: Int(line.split(separator: ",")[1])!)
print("\(item.formatted) \(item.isAffordable(budget: budget) ? "yes" : "no")")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الأصناف والكائنات
العمل مع الملفاتتعريف الأصنافالأساليب وselfالمُهيِّئاتالأصناف هي مراجعمراجعة - بطاقة المكتبة4التغليف
التحكم في الوصولللقراءة فقط من الخارجحماية الحالةالمهيئات القابلة للفشلمراجعة - الحساب البنكي7تعدد الأشكال والأنواع العامة
تعدد الأشكالتحويل الأنواعالدوال العامةالأنواع العامةمراجعة - حاسبة الأشكال3الخصائص بتعمّق
الخصائص المحسوبةمراقبو الخصائصالأعضاء الثابتةالتعدادات مع الدوالمراجعة - سجل درجات الحرارة6البروتوكولات
تعريف البروتوكولاتالأنواع المتوافقةامتدادات البروتوكولاتالبروتوكولات كأنواعمراجعة - نظام الدفعتدرّب بنفسك: Playground لـ Swift