Facade: أساسيات نمط الواجهة في العمارة المتنقلة

المؤلف: IT Sectr نُشر: 2026-02-18 وقت القراءة: 9 دق

Facade هو نمط تصميم هيكلي يوفر واجهة مبسّطة لنظام فرعي معقد من الفئات. في تطوير التطبيقات المتنقلة، يُنفَّذ Facade غالباً كـ Service Layer أو UseCase، مخفياً التفاعل مع الشبكة وقاعدة البيانات والتحليلات. وفقاً لـ Martin Fowler (Patterns of Enterprise Application Architecture, 2003)، يعد Facade من الأنماط الرئيسية لتنظيم طبقة الخدمات.

الأساسيات

  • Facade — نمط هيكلي يوفر واجهة بسيطة لنظام معقد من الفئات أو المكتبات أو الأطر
  • Service Layer — تطبيق Facade في العمارة المتنقلة يخفي API والكاش والتحليلات عن الواجهة UI
  • Facade لا يخفي النظام الفرعي — يمكن للعميل الوصول إليه مباشرة عند الحاجة
  • UseCase في Clean Architecture — نوع من Facade ينظّم سيناريو أعمال واحداً
  • Facade مقابل Adapter: Facade يبسّط الواجهة، بينما Adapter يحوّل واجهة إلى أخرى

ما هو نمط Facade؟

Facade نمط هيكلي يوفر واجهة موحّدة لمجموعة من واجهات النظام الفرعي. يحدد واجهة عالية المستوى تبسّط استخدام النظام الفرعي. Facade لا يضيف وظائف جديدة — بل ينظّم المكونات الموجودة، مخفياً تعقيد تفاعلها عن العميل.

Kotlin
// نظام فرعي معقد
class AuthApi {
    suspend fun login(email: String, pass: String): TokenResponse
}

class UserDao {
    suspend fun saveUser(user: UserEntity)
    suspend fun getUser(id: Long): UserEntity?
}

class AnalyticsTracker {
    fun track(event: String, params: Map)
}

// Facade — واجهة بسيطة للواجهة UI
class AuthService(
    private val api: AuthApi,
    private val dao: UserDao,
    private val analytics: AnalyticsTracker
) {
    suspend fun loginUser(email: String, password: String): Result {
        return runCatching {
            val token = api.login(email, password)
            val user = User(token.userId, email, token.accessToken)
            dao.saveUser(user.toEntity())
            analytics.track("login_success", mapOf("method" to "email"))
            user
        }
    }
}

AuthService هو Facade يخفي AuthApi وUserDao وAnalyticsTracker عن ViewModel. يستدعي UI دالة loginUser(email, password) بدلاً من ثلاثة طلبات منفصلة إلى API وقاعدة البيانات والتحليلات. هذا يقلل الاقتران: إذا أصبح AuthApi غداً FirebaseAuth أو انتقل UserDao إلى Room، فلن يتغير سوى Facade وليس UI.

Facade في العمارة المتنقلة: Service Layer

Service Layer تطبيق شائع لـ Facade في التطبيقات المتنقلة. يغلّف منطق الأعمال والتنسيق بين الطبقات. في Android، يُنفَّذ Service Layer غالباً عبر UseCase (Clean Architecture)، وفي iOS عبر بروتوكولات Manager أو Service.

المكوّن الدور في النظام الفرعي ما يخفيه Facade
AuthApi طلب شبكة إلى الخادم تنسيق الطلب ونقطة النهاية ومعالجة أخطاء HTTP
UserDao التخزين المحلي للرمز المميّز مخطط قاعدة البيانات واستعلامات SQL والترحيلات
AnalyticsTracker إرسال أحداث التحليلات Firebase/AppMetrica SDK وتنسيق الأحداث
NetworkMonitor التحقق من توفر الشبكة ConnectivityManager وBroadcastReceiver

AuthService يجمع المكونات الأربعة جميعها. يستدعي ViewModel طريقة واحدة دون معرفة أنه خلف الكواليس يحدث طلب شبكة وكتابة في قاعدة البيانات وتتبع وفحص للشبكة. عند الاختبار، يمكن استبدال AuthService بـ mock للتحقق من منطق المصادقة بالكامل دون التكامل مع المكونات الحقيقية.

Facade مقابل Adapter مقابل Mediator

Facade وAdapter وMediator أنماط هيكلية، لكنها تحل مشكلات مختلفة. غالباً ما يُخلط بينها لأن الثلاثة تُدخل كائناً وسيطاً. لنحلل الاختلافات بمثال تطبيق متنقل.

الجانب Facade Adapter Mediator
الهدف تبسيط واجهة النظام الفرعي تحويل واجهة تقليل الاقتران بين المكونات
الاتجاه واجهة واحدة ← النظام الفرعي العميل ← Adaptee N مكون ↔ Mediator
تغيير الواجهة ينشئ واجهة جديدة مبسّطة يحوّل الواجهة الموجودة لا يغيّرها، بل ينسّق
هل يعرف النظام الفرعي النمط؟ لا لا نعم، يتواصل عبر Mediator
مثال في التطوير المتنقل UseCase / Service Layer RecyclerView.Adapter Coordinator في iOS

Facade لا يخفي النظام الفرعي — يمكن للعميل الوصول إلى AuthApi مباشرة عند الحاجة. Adapter يغيّر واجهة Adaptee إلزامياً. Mediator ينسّق التفاعلات المعقدة بين كائنات عديدة قد لا تعرف بعضها البعض.

تطبيق Facade بلغة Kotlin لنظام Android

تطبيق Facade بلغة Kotlin لنظام Android مع Clean Architecture يستخدم UseCase كنقطة دخول لكل سيناريو أعمال. UseCase هو Facade يخفي المستودع والمنظّم (mapper) والتبعيات الأخرى عن طبقة UI.

Kotlin
// Repository هو أيضاً Facade، لكن بمستوى أدنى
class UserRepositoryImpl(
    private val local: UserLocalDataSource,
    private val remote: UserRemoteDataSource,
    private val mapper: UserMapper
) : UserRepository {
    override suspend fun getUserProfile(id: String): UserProfile {
        val cached = local.getUser(id)
        if (cached != null && !cached.isStale) {
            return mapper.toProfile(cached)
        }
        val dto = remote.fetchUser(id)
        val entity = mapper.toEntity(dto)
        local.saveUser(entity)
        return mapper.toProfile(entity)
    }
}

// UseCase — Facade لسيناريو الأعمال
class LoadUserProfileUseCase(
    private val repo: UserRepository,
    private val analytics: AnalyticsTracker
) {
    suspend operator fun invoke(userId: String): Result {
        return runCatching {
            val profile = repo.getUserProfile(userId)
            analytics.track("profile_loaded", mapOf("user_id" to userId))
            profile
        }
    }
}

LoadUserProfileUseCase هو Facade لسيناريو تحميل الملف الشخصي. يخفي منطق التخزين المؤقت (local ← remote) وتحويل DTO ← Entity ← Profile وتتبع التحليلات. يستدعي ViewModel دالة invoke(userId) ويحصل على UserProfile جاهز أو خطأ. يمكن اختبار UseCase بشكل معزول باستبدال المستودع بكائن mock.

تطبيق Facade بلغة Swift لنظام iOS

Facade في iOS يُنفَّذ غالباً كـ Manager أو Service. على عكس Android، يستخدم iOS البروتوكولات لتحديد واجهة Facade، ما يسمح بتبديل التطبيقات بسهولة في الاختبارات. لننظر إلى Facade للعمل مع الوسائط — التحميل والتخزين المؤقت والعرض.

Swift
protocol MediaServiceProtocol {
    func loadImage(from url: URL) async -> Result<UIImage, Error>
}

final class MediaService: MediaServiceProtocol {
    private let cache: ImageCache
    private let downloader: ImageDownloader
    private let decoder: ImageDecoder
    
    func loadImage(from url: URL) async -> Result<UIImage, Error> {
        // 1. فحص الكاش
        if let cached = cache.image(for: url) {
            return .success(cached)
        }
        // 2. تحميل البيانات
        let result = await downloader.download(from: url)
        guard case let .success(data) = result else {
            return .failure(MediaError.downloadFailed)
        }
        // 3. فك الترميز
        guard let image = decoder.decode(data) else {
            return .failure(MediaError.decodeFailed)
        }
        // 4. الحفظ في الكاش
        cache.setImage(image, for: url)
        return .success(image)
    }
}

MediaService يغلّف عملية من ثلاث خطوات: الكاش ← التحميل ← فك الترميز. يستدعي UI طريقة واحدة loadImage(from:) بدلاً من إدارة ImageCache وURLSession وImageDecoder. عند الاختبار، يمكن استبدال MediaServiceProtocol بـ mock يعيد صوراً محددة مسبقاً دون تحميل حقيقي.

الأخطاء الشائعة عند استخدام Facade

الأخطاء عند تصميم Facade تلغي مزاياه: بدلاً من التبسيط تحصل على God Object يعتمد عليه النظام بأكمله. لنحلل المشكلات الثلاث الرئيسية.

God Facade — مسؤولية زائدة

عندما يحتوي Facade واحد على طرق للمصادقة وتحميل الملف الشخصي وإرسال الرسائل والمزامنة — فهذا God Object. علامة: أكثر من 15 طريقة عامة في فئة واحدة. الحل: تقسيمه إلى عدة Facade متخصصة حسب مجالات المسؤولية — AuthService وProfileService وMessagingService.

Facade مع تسريب تفاصيل النظام الفرعي

إذا أعاد Facade أنواعاً خاصة بالنظام الفرعي (على سبيل المثال، FirebaseUser أو RealmObject)، فإن العميل يظل مرتبطاً بتطبيق محدد. الحل: يجب أن يعيد Facade أنواعه الخاصة فقط (data class / struct)، مما يجرّد العميل تماماً من تفاصيل النظام الفرعي.

Facade كنقطة دخول وحيدة

عندما يمنع Facade الوصول المباشر إلى النظام الفرعي، يصبح عنق زجاجة. أحياناً يحتاج العميل طريقة محددة من النظام الفرعي، وإجباره على المرور عبر Facade أمر زائد. يجب ألا يكون Facade بوابة صارمة: يوفر واجهة مريحة لكنه لا يحجب الوصول المباشر إلى المكونات.

الأسئلة الشائعة

ما الفرق بين Facade وProxy؟

Facade يوفر واجهة مبسّطة للنظام الفرعي، وغالباً ما ينشئ مجموعة طرق جديدة. Proxy يحافظ على نفس واجهة الكائن الأصلي، لكنه يضيف التحكم في الوصول أو التحميل الكسول. Facade للتبسيط، وProxy للتحكم.

هل Facade هو نفسه Service Layer؟

Service Layer هو تطبيق لنمط Facade على مستوى عمارة التطبيق. يحدد الحدود بين UI ومنطق الأعمال، مخفياً تفاصيل تنفيذ الخدمات. في Android، يُنفَّذ Service Layer غالباً عبر UseCase؛ وفي iOS عبر بروتوكولات Manager أو Service.

متى يصبح Facade God Object؟

God Facade ينشأ عندما تتولى فئة واحدة مسؤولية عدة أنظمة فرعية غير مرتبطة. العلامات: أكثر من 15 طريقة عامة، طرق من مجالات مختلفة (المصادقة + المدفوعات + الإشعارات)، فئة يصعب اختبارها (أكثر من 10 تبعيات). الحل: تقسيمها إلى Facade مجال.

هل يحتاج التطبيق الصغير إلى Facade؟

في تطبيق من 1-2 شاشة، يكون Facade زائداً — استدعاء API وقاعدة البيانات مباشرة من UI أبسط وأوضح. يؤتي Facade ثماره مع 5+ شاشات و3+ أنظمة فرعية. في المشاريع الصغيرة والمتوسطة يكفي Repository كطبقة Facade وحيدة دون غلاف UseCase إضافي.

كيف نختبر الكود الذي يستخدم Facade؟

Facade يبسّط الاختبار لأنه يستبدل النظام الفرعي بأكمله بكائن mock واحد. بدلاً من محاكاة ثلاثة مكونات (شبكة + قاعدة بيانات + تحليلات)، يكفي محاكاة Facade واحد. في Swift تُستخدم البروتوكولات لهذا الغرض، وفي Kotlin الواجهات. كما أن Facade مناسب لاختبارات التكامل التي تتحقق من تنسيق المكونات.

الخلاصة

  • Facade — نمط هيكلي يوفر واجهة بسيطة لنظام فرعي معقد
  • Service Layer وUseCase — تطبيقات شائعة لـ Facade في العمارة المتنقلة
  • Facade لا يخفي النظام الفرعي: يمكن للعميل الوصول إلى المكونات مباشرة عند الحاجة
  • Facade مقابل Adapter: Facade يبسّط وAdapter يحوّل؛ Facade مقابل Mediator: Facade أحادي الاتجاه وMediator ثنائي الاتجاه
  • God Facade — نمط مضاد: أكثر من 15 طريقة في فئة واحدة تشير إلى انتهاك مبدأ المسؤولية الواحدة
  • البروتوكول/الواجهة لـ Facade ضروري — هو الطريقة الوحيدة لاختبار النظام الفرعي باستخدام mocks
  • توصية: أدخل Facade مع 5+ شاشات و3+ أنظمة فرعية؛ للمشاريع الصغيرة يكفي Repository

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا