Protocol Extension هي آلية في Swift تسمح بتوفير تطبيقات افتراضية للطرق والخصائص للبروتوكول. وبالجمع مع قيود where، تتيح protocol extension إضافة سلوك فقط للأنواع التي تستوفي شروطًا معينة. وفقًا Apple Documentation, 2026، هذا عنصر أساسي في البرمجة الموجهة بالبروتوكولات، مما يتيح إعادة استخدام الكود دون تسلسلات هرمية للفئات.
الخلاصة
Protocol Extension هي طريقة لإضافة تطبيقات للطرق والخصائص المحسوبة إلى بروتوكول موجود. بدون الامتدادات، يحدد البروتوكول المتطلبات فقط، وينفذها كل نوع على حدة.
Protocol Extension تحل مشكلة تكرار الكود: إذا اعتمدت خمس structs نفس البروتوكول ونفذت نفس الطريقة، فإن الامتداد يوفر التطبيق الافتراضي مرة واحدة.
وفقًا Swift Evolution proposal SE-0186، فإن protocol extensions هي إحدى الميزات الرئيسية التي حددت نجاح POP. إنها تسمح بإضافة سلوك مشترك دون إنشاء فئات أساسية ودون انتهاك مبدأ المسؤولية الفردية.
يتم تعريف Protocol Extension كامتداد عادي ولكن باسم البروتوكول بدلاً من النوع.
protocol Greetable {
var name: String { get }
func greet() -> String
}
extension Greetable {
func greet() -> String {
return "Hello, \(name)!"
}
}
الآن أي نوع يتبنى Greetable يحصل تلقائيًا على تطبيق greet:
struct Person: Greetable {
let name: String
}
// يمتلك Person تلقائيًا greet()
let user = Person(name: "Alice")
print(user.greet()) // "مرحبًا أليس!"
يمكن أن تحتوي Protocol Extension على خصائص محسوبة ولكن ليس خصائص مخزنة (لا يمكن للبروتوكولات تحديد تخزين). يمكنك أيضًا إضافة رموز فرعية وأنواع متداخلة من خلال الامتدادات.
التطبيق الافتراضي هو الاستخدام الرئيسي لـ protocol extension. يمكن للنوع تجاوز الطريقة من خلال توفير نسخته الخاصة.
protocol Loggable {
func log(message: String)
}
extension Loggable {
func log(message: String) {
print("[Default] \(message)")
}
}
struct ConsoleLogger: Loggable {}
// يستخدم التطبيق الافتراضي
struct FileLogger: Loggable {
func log(message: String) {
// التطبيق المخصص يتجاوز الافتراضي
writeToFile(message)
}
}
فرق مهم عن وراثة الفئات: إذا نفذ النوع نفسه طريقة البروتوكول، يتم استدعاء تطبيقه. إذا لم يفعل، يتم استخدام التطبيق الافتراضي من الامتداد. هذا هو الإرسال الثابت — يتم اتخاذ القرار في وقت الترجمة.
جملة where تسمح بتقييد protocol extension فقط للأنواع التي تستوفي شروطًا إضافية. هذه آلية قوية لإضافة سلوك متخصص.
protocol Printable {
var content: String { get }
}
extension Printable where Self: CustomStringConvertible {
func debugPrint() -> String {
return "[Printable] \(content)"
}
}
هنا debugPrint متاح فقط للأنواع التي تنفذ في نفس الوقت Printable و CustomStringConvertible. المكتبة القياسية Swift تستخدم هذا النمط على نطاق واسع — على سبيل المثال، امتدادات لـ Collection حيث Element.
جمل where مع قيود مساواة النوع مفيدة بشكل خاص:
extension Collection where Element == String {
func commaJoined() -> String {
return self.joined(separator: ", ")
}
}
let words = ["Swift", "Kotlin", "Java"]
print(words.commaJoined()) // "Swift, Kotlin, Java"
هذه الآلية تجعل protocol extension انتقائيًا: طريقة commaJoined متاحة فقط لمجموعات السلاسل النصية، وليس للمجموعات الرقمية. يتحقق المترجم من القيود بشكل ثابت.
يمكن لقيود where التحقق من:
where Self: Equatablewhere Element == Stringwhere Element: Numeric, Element: Comparableهذا يجعل protocol extension آلية قوية لإضافة سلوك متخصص دون تلويث تطبيق البروتوكول العام.
يتساءل العديد من المطورين: متى نستخدم protocol extensions ومتى نستخدم وراثة الفئات؟ تعتمد الإجابة على النموذج المعماري.
| الخاصية | Protocol Extension | وراثة الفئات |
|---|---|---|
| أنواع القيم | يعمل مع struct و enum | فئات فقط |
| التبني المتعدد | يمكن للنوع تبني بروتوكولات متعددة | فئة أصل واحدة |
| الحالة | لا خصائص مخزنة | يمكن أن تحتوي على خصائص مخزنة |
| الإرسال | إرسال ثابت (افتراضي) | إرسال ديناميكي (جداول افتراضية) |
توصي Apple بالبدء بـ protocol + extension والتحول إلى الفئات فقط عند الحاجة إلى حالة مشتركة أو هوية (دلالات مرجعية). توفر protocol extensions التكوين بدلاً من الوراثة — نهج أكثر مرونة وقابلية للاختبار.
في الممارسة العملية، تُستخدم protocol extensions غالبًا لإضافة طرق تغليف ملائمة أعلى متطلبات البروتوكول. على سبيل المثال، إذا كان البروتوكول يتطلب طريقة validate بتقرير مفصل، يمكن للامتداد إضافة طريقة isValid التي تُرجع قيمة منطقية بناءً على النسخة الكاملة. هذا يبسط كود العميل دون تغيير عقد البروتوكول. يُسمى هذا النمط «تطبيق افتراضي مع API مشتقة» ويستخدم على نطاق واسع في المكتبة القياسية لـ Swift والأطر الخارجية الشهيرة. إنها إحدى التقنيات الرئيسية للبرمجة الموجهة بالبروتوكولات وأساس العمارة المرنة.
الأسئلة الشائعة
لا، يمكن أن تحتوي protocol extension على خصائص محسوبة فقط. الخصائص المخزنة محظورة لأن البروتوكول لا يمتلك ذاكرة — النوع المحدد (struct, class, enum) مسؤول عن تخزين البيانات.
يتم استخدام الإرسال الثابت: إذا نفذ النوع الطريقة بشكل صريح، يتم استدعاء نسخته. إذا لم يفعل، يتم استخدام الافتراضي من الامتداد. عند الوصول من خلال existential (any)، يتم تطبيق الإرسال الديناميكي.
نعم، يمكن أن تحتوي protocol extension على مهيئات. ومع ذلك، لا يمكن للبروتوكول أن يتطلب init من خلال الامتداد — يجب أن يكون المتطلب في إعلان البروتوكول والتطبيق في النوع.
Protocol extension تنطبق على جميع الأنواع التي تتبنى البروتوكول. امتداد النوع ينطبق فقط على نوع محدد واحد. توفر protocol extensions تعدد الأشكال دون وراثة.
لا، Swift يمنع protocol extensions المتداخلة. يتم تعريف كل protocol extension على مستوى الملف. استخدم علامات // MARK: وملفات منفصلة لتنظيم الكود.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.