Protocol Extension در Swift: چیست و چگونه استفاده کنیم

نویسنده: IT Sectr منتشر شده: 2026-06-18 زمان مطالعه: 6 دقیقه

Protocol Extension — مکانیسمی در Swift که اجازه می‌دهد پیاده‌سازی پیش‌فرض روش‌ها و ویژگی‌ها را برای پروتکل فراهم کنیم. در ترکیب با محدودیت‌های where، protocol extension امکان افزودن رفتار را فقط به آن تیپ‌هایی می‌دهد که شرایط مشخصی را برآورده کنند. به گزارش Apple Documentation, 2026، این یک عنصر کلیدی برنامه‌نویسی پروتکل-محور است که امکان استفاده مجدد از کد را بدون سلسله‌مراتب کلاس‌ها فراهم می‌کند.

نکات کلیدی

  • Protocol Extension — پیاده‌سازی پیش‌فرض روش‌ها برای پروتکل
  • Default implementation از تکرار کد در تیپ‌ها جلوگیری می‌کند
  • Where clauses extension را فقط به تیپ‌های مشخصی محدود می‌کنند
  • بازنویسی — تیپ می‌تواند به جای مقدار پیش‌فرض، پیاده‌سازی خود را ارائه دهد
  • POP — protocol extensions جایگزین کلاس‌های پایه در OOP می‌شوند

Protocol Extension چیست؟

Protocol Extension — راهی است برای افزودن پیاده‌سازی روش‌ها و ویژگی‌های قابل محاسبه به پروتکل موجود. بدون extension، پروتکل فقط نیازمندی‌ها را تعریف می‌کند و هر تیپ آنها را مستقلاً پیاده‌سازی می‌کند.

Protocol Extension مشکل تکرار کد را حل می‌کند: اگر پنج ساختار یک پروتکل را قبول کنند و روش یکسانی را پیاده‌سازی کنند، extension پیاده‌سازی پیش‌فرض را یک بار ارائه می‌دهد.

به گزارش Swift Evolution proposal SE-0186، protocol extensions یکی از امکانات کلیدی است که موفقیت POP را تعیین کرده‌اند. آنها امکان افزودن رفتار مشترک را بدون ایجاد کلاس‌های پایه و بدون نقض اصل مسئولیت مفرد فراهم می‌کنند.

سینتاکس protocol extension

Protocol Extension مانند یک extension عادی اعلام می‌شود، اما به جای نام تیپ، با نام پروتکل.

swift
protocol Greetable {
    var name: String { get }
    func greet() -> String
}

extension Greetable {
    func greet() -> String {
        return "Hello, \(name)!"
    }
}

حال هر تیپی که Greetable را قبول کند، به‌طور خودکار پیاده‌سازی greet را دریافت می‌کند:

swift
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. تیپ می‌تواند روش را بازنویسی کند و نسخه خود را ارائه دهد.

swift
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 در protocol extension

Where clause امکان محدود کردن protocol extension را فقط به آن تیپ‌هایی می‌دهد که شرایط اضافی را برآورده کنند. این یک مکانیسم قوی برای افزودن رفتار تخصصی است.

swift
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 با محدودیت برابری نوع مفید هستند:

swift
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: Equatable
  • محدودیت نوع: where Element == String
  • ترکیبات: where Element: Numeric, Element: Comparable

این protocol extension را به یک مکانیسم قوی برای افزودن رفتار تخصصی بدون آلودگی پیاده‌سازی عمومی پروتکل تبدیل می‌کند.

Protocol Extensions در مقابل وراثت

بسیاری از توسعه‌دهندگان سوال می‌کنند: کی از 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 property داشته باشد؟

خیر، protocol extension فقط می‌تواند ویژگی‌های قابل محاسبه داشته باشد. Stored properties ممنوع هستند، زیرا پروتکل مالک حافظه نیست — نوع مشخص (struct, class, enum) مسئول ذخیره‌سازی داده‌ها است.

Protocol extension چگونه پیاده‌سازی را در بازنویسی انتخاب می‌کند؟

از ارسال ساکن استفاده می‌شود: اگر تیپ روش را به‌صراحت پیاده‌سازی کند — نسخه آن فراخوانده می‌شود. در غیر این صورت — مقدار پیش‌فرض از extension. در حالت دسترسی از طریق existential (any)، dynamic dispatch اعمال می‌شود.

آیا می‌توان convenience init را در protocol extension اضافه کرد؟

بله، protocol extension می‌تواند شروع‌کننده داشته باشد. اما پروتکل نمی‌تواند init را از طریق extension نیاز داشته باشد — نیاز باید در اعلان پروتکل باشد، و پیاده‌سازی در نوع.

تفاوت protocol extension با extension برای نوع مشخص چیست؟

Protocol extension برای همه تیپ‌هایی اعمال می‌شود که پروتکل را قبول کرده‌اند. Extension برای نوع — فقط برای یک نوع مشخص. Protocol extension بدون وراثت چندشکلی ایجاد می‌کند.

آیا می‌توان protocol extension را درون یک extension دیگر قرار داد؟

خیر، Swift protocol extensions تودرفته را ممنوع می‌کند. هر protocol extension در سطح فایل اعلام می‌شود. برای سازماندهی کد از علامت‌گذارهای // MARK: و فایل‌های جداگانه استفاده کنید.

نتیجه‌گیری

  • Protocol Extension — پیاده‌سازی پیش‌فرض روش‌ها برای همه تیپ‌هایی که پروتکل را قبول کرده‌اند
  • Where clause extension را فقط به تیپ‌های مشخصی محدود می‌کند
  • Default implementation تکرار کد را بین تیپ‌ها از بین می‌برد
  • Computed properties مجاز هستند، stored properties — نخیر
  • Static dispatch — اگر تیپ روش را بازنویسی نکرده باشد، پیاده‌سازی پیش‌فرض فراخوانده می‌شود
  • POP با protocol extensions جایگزین وراثت شده و معماری را انعطاف‌پذیرتر می‌کند

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید