Protocol Extension — مکانیسمی در Swift که اجازه میدهد پیادهسازی پیشفرض روشها و ویژگیها را برای پروتکل فراهم کنیم. در ترکیب با محدودیتهای where، protocol extension امکان افزودن رفتار را فقط به آن تیپهایی میدهد که شرایط مشخصی را برآورده کنند. به گزارش Apple Documentation, 2026، این یک عنصر کلیدی برنامهنویسی پروتکل-محور است که امکان استفاده مجدد از کد را بدون سلسلهمراتب کلاسها فراهم میکند.
نکات کلیدی
Protocol Extension — راهی است برای افزودن پیادهسازی روشها و ویژگیهای قابل محاسبه به پروتکل موجود. بدون extension، پروتکل فقط نیازمندیها را تعریف میکند و هر تیپ آنها را مستقلاً پیادهسازی میکند.
Protocol Extension مشکل تکرار کد را حل میکند: اگر پنج ساختار یک پروتکل را قبول کنند و روش یکسانی را پیادهسازی کنند، extension پیادهسازی پیشفرض را یک بار ارائه میدهد.
به گزارش Swift Evolution proposal SE-0186، protocol extensions یکی از امکانات کلیدی است که موفقیت POP را تعیین کردهاند. آنها امکان افزودن رفتار مشترک را بدون ایجاد کلاسهای پایه و بدون نقض اصل مسئولیت مفرد فراهم میکنند.
Protocol Extension مانند یک 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()) // «Hello, Alice!»
Protocol Extension میتواند ویژگیهای قابل محاسبه داشته باشد، اما stored properties نخیر (پروتکلها نمیتوانند حافظه تعریف کنند). شما میتوانید از طریق extension، subscripts و انواع تودرفته نیز اضافه کنید.
Default implementation — کاربرد اصلی 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)
}
}
تفاوت مهم با وراثت کلاس: اگر تیپ خودش روش پروتکل را پیادهسازی کند، پیادهسازی آن فراخوانده میشود. در غیر این صورت — مقدار پیشفرض از extension استفاده میشود. این ارسال ساکن است، تصمیم در مرحله کامپایل گرفته میشود.
Where clause امکان محدود کردن protocol extension را فقط به آن تیپهایی میدهد که شرایط اضافی را برآورده کنند. این یک مکانیسم قوی برای افزودن رفتار تخصصی است.
protocol Printable {
var content: String { get }
}
extension Printable where Self: CustomStringConvertible {
func debugPrint() -> String {
return "[Printable] \(content)"
}
}
در اینجا debugPrint فقط برای تیپهایی قابل دسترس است که همزمان Printable و CustomStringConvertible را پیادهسازی میکنند. Swift کتابخانه استاندارد از این الگو بهطور گسترده استفاده میکند — به عنوان مثال، extension برای Collection where Element.
بهویژه where clauses با محدودیت برابری نوع مفید هستند:
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 constraints میتوانند موارد زیر را بررسی کنند:
where Self: Equatablewhere Element == Stringwhere Element: Numeric, Element: Comparableاین protocol extension را به یک مکانیسم قوی برای افزودن رفتار تخصصی بدون آلودگی پیادهسازی عمومی پروتکل تبدیل میکند.
بسیاری از توسعهدهندگان سوال میکنند: کی از protocol extensions استفاده کنیم و کی از وراثت کلاس؟ پاسخ به پارادایم معماری بستگی دارد.
| ویژگی | Protocol Extension | وراثت کلاس |
|---|---|---|
| Value types | با struct و enum کار میکند | فقط کلاسها |
| کاربرد چندگانه | تیپ میتواند چندین پروتکل را بپذیرد | یک سوپرکلاس |
| وضعیت | هیچ stored properties | میتواند stored properties داشته باشد |
| ارسال | Static dispatch (پیشفرض) | Dynamic dispatch (جداول مجازی) |
Apple توصیه میکند با protocol + extension شروع کنید و فقط در صورت نیاز به وضعیت مشترک یا هویت (reference semantics) به کلاسها مراجعه کنید. Protocol extensions به جای وراثت، ترکیب را ارائه میدهند — رویکردی انعطافپذیرتر و قابل آزمایشتر.
در عمل، protocol extensions اغلب برای افزودن روشهای راحت پیچیده بر روی نیازمندیهای پروتکل استفاده میشوند. به عنوان مثال، اگر پروتکل روش validate را با گزارش مفصل نیاز داشته باشد، extension میتواند روش isValid را اضافه کند که بر اساس نسخه کامل مقدار بولیان بازگرداند. این کد مشترک را بدون تغییر قرارداد پروتکل سادهتر میکند. این الگو «default implementation با derived API» نامیده میشود و در کتابخانه استاندارد Swift و چارچوبهای شخص ثالث محبوب بهطور گسترده استفاده میشود. این یکی از تکنیکهای کلیدی برنامهنویسی پروتکل-محور در عمل و اساس معماری انعطافپذیر است.
سوالات متداول
خیر، protocol extension فقط میتواند ویژگیهای قابل محاسبه داشته باشد. Stored properties ممنوع هستند، زیرا پروتکل مالک حافظه نیست — نوع مشخص (struct, class, enum) مسئول ذخیرهسازی دادهها است.
از ارسال ساکن استفاده میشود: اگر تیپ روش را بهصراحت پیادهسازی کند — نسخه آن فراخوانده میشود. در غیر این صورت — مقدار پیشفرض از extension. در حالت دسترسی از طریق existential (any)، dynamic dispatch اعمال میشود.
بله، protocol extension میتواند شروعکننده داشته باشد. اما پروتکل نمیتواند init را از طریق extension نیاز داشته باشد — نیاز باید در اعلان پروتکل باشد، و پیادهسازی در نوع.
Protocol extension برای همه تیپهایی اعمال میشود که پروتکل را قبول کردهاند. Extension برای نوع — فقط برای یک نوع مشخص. Protocol extension بدون وراثت چندشکلی ایجاد میکند.
خیر، Swift protocol extensions تودرفته را ممنوع میکند. هر protocol extension در سطح فایل اعلام میشود. برای سازماندهی کد از علامتگذارهای // MARK: و فایلهای جداگانه استفاده کنید.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.