Facade একটি স্ট্রাকচারাল ডিজাইন প্যাটার্ন যা ক্লাসের জটিল সাবসিস্টেমের জন্য একটি সরলীকৃত ইন্টারফেস প্রদান করে। মোবাইল ডেভেলপমেন্টে, Facade প্রায়শই Service Layer বা UseCase হিসেবে বাস্তবায়িত হয়, যা নেটওয়ার্ক, ডেটাবেস এবং অ্যানালিটিক্সের সাথে মিথস্ক্রিয়া লুকিয়ে রাখে। Martin Fowler-এর মতে (Patterns of Enterprise Application Architecture, 2003), সার্ভিস লেয়ার সংগঠিত করার জন্য Facade অন্যতম মূল প্যাটার্ন।
মূল বিষয়
Facade একটি স্ট্রাকচারাল প্যাটার্ন যা সাবসিস্টেম ইন্টারফেসের একটি গোষ্ঠীর জন্য একটি একীভূত ইন্টারফেস প্রদান করে। এটি একটি উচ্চ-স্তরের ইন্টারফেস নির্ধারণ করে যা সাবসিস্টেমের ব্যবহার সহজ করে। Facade নতুন কার্যকারিতা যোগ করে না — এটি বিদ্যমান উপাদানগুলোকে অর্কেস্ট্রেট করে, ক্লায়েন্টের কাছ থেকে তাদের মিথস্ক্রিয়ার জটিলতা লুকিয়ে রাখে।
// জটিল সাবসিস্টেম
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 যা ViewModel থেকে AuthApi, UserDao এবং AnalyticsTracker লুকিয়ে রাখে। UI API, ডেটাবেস এবং অ্যানালিটিক্সে তিনটি আলাদা অনুরোধের পরিবর্তে loginUser(email, password) কল করে। এটি কাপলিং কমায়: যদি কাল AuthApi FirebaseAuth হয়ে যায় বা UserDao Room-এ মাইগ্রেট হয়, তাহলে শুধু Facade বদলায়, UI নয়।
Service Layer মোবাইল অ্যাপ্লিকেশনে Facade-এর একটি সাধারণ বাস্তবায়ন। এটি ব্যবসায়িক লজিক এবং লেয়ারগুলোর মধ্যে সমন্বয়কে এনক্যাপসুলেট করে। Android-এ, Service Layer প্রায়শই UseCase (Clean Architecture) এর মাধ্যমে বাস্তবায়িত হয়, আর iOS-এ Manager বা Service প্রোটোকলের মাধ্যমে।
| উপাদান | সাবসিস্টেমে ভূমিকা | Facade কী লুকিয়ে রাখে |
|---|---|---|
| AuthApi | সার্ভারে নেটওয়ার্ক অনুরোধ | অনুরোধের ফরম্যাট, endpoint, HTTP ত্রুটি হ্যান্ডলিং |
| UserDao | টোকেনের স্থানীয় সংরক্ষণ | ডেটাবেস স্কিমা, SQL কোয়েরি, মাইগ্রেশন |
| AnalyticsTracker | অ্যানালিটিক্স ইভেন্ট পাঠানো | Firebase/AppMetrica SDK, ইভেন্ট ফরম্যাট |
| NetworkMonitor | নেটওয়ার্ক প্রাপ্যতা যাচাই | ConnectivityManager, BroadcastReceiver |
AuthService চারটি উপাদানকেই একত্রিত করে। ViewModel একটি মাত্র মেথড কল করে, না জেনে যে ভেতরে নেটওয়ার্ক অনুরোধ, ডেটাবেস লেখা, ট্র্যাকিং এবং নেটওয়ার্ক যাচাই হচ্ছে। পরীক্ষার সময়, AuthService-কে mock দিয়ে প্রতিস্থাপন করা যায়, প্রকৃত উপাদানের সাথে ইন্টিগ্রেশন ছাড়াই পুরো প্রমাণীকরণ লজিক যাচাই করা যায়।
Facade, Adapter এবং Mediator স্ট্রাকচারাল প্যাটার্ন, কিন্তু এরা ভিন্ন সমস্যা সমাধান করে। এদের প্রায়ই গুলিয়ে ফেলা হয়, কারণ তিনটিই একটি মধ্যস্থ বস্তু প্রবর্তন করে। মোবাইল অ্যাপ্লিকেশনের উদাহরণ দিয়ে পার্থক্য বিশ্লেষণ করি।
| দিক | Facade | Adapter | Mediator |
|---|---|---|---|
| উদ্দেশ্য | সাবসিস্টেম ইন্টারফেস সরল করা | ইন্টারফেস রূপান্তর করা | উপাদানের কাপলিং কমানো |
| দিক | একটি ইন্টারফেস → সাবসিস্টেম | ক্লায়েন্ট → Adaptee | N উপাদান ↔ Mediator |
| ইন্টারফেস পরিবর্তন | নতুন, সরলীকৃত তৈরি করে | বিদ্যমানটি রূপান্তর করে | পরিবর্তন করে না, সমন্বয় করে |
| সাবসিস্টেম কি প্যাটার্ন সম্পর্কে জানে? | না | না | হ্যাঁ, Mediator-এর মাধ্যমে যোগাযোগ করে |
| মোবাইল ডেভেলপমেন্টে উদাহরণ | UseCase / Service Layer | RecyclerView.Adapter | iOS-এ Coordinator |
Facade সাবসিস্টেম লুকিয়ে রাখে না — ক্লায়েন্ট প্রয়োজন হলে সরাসরি AuthApi-তে প্রবেশ করতে পারে। Adapter বাধ্যতামূলকভাবে Adaptee-এর ইন্টারফেস পরিবর্তন করে। Mediator অনেক বস্তুর মধ্যে জটিল মিথস্ক্রিয়া সমন্বয় করে, যারা একে অপরের সম্পর্কে জানতে পারে না।
Facade বাস্তবায়ন Kotlin-এ Android-এর জন্য Clean Architecture সহ প্রতিটি ব্যবসায়িক পরিস্থিতির জন্য UseCase-কে প্রবেশ বিন্দু হিসেবে ব্যবহার করে। UseCase একটি Facade যা রিপোজিটরি, ম্যাপার এবং অন্যান্য নির্ভরতাকে UI লেয়ার থেকে লুকিয়ে রাখে।
// 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 বস্তু দিয়ে প্রতিস্থাপন করে বিচ্ছিন্নভাবে পরীক্ষা করা যায়।
iOS-এ Facade প্রায়শই Manager বা Service হিসেবে বাস্তবায়িত হয়। Android-এর বিপরীতে, iOS Facade-এর ইন্টারফেস নির্ধারণের জন্য প্রোটোকল ব্যবহার করে, যা পরীক্ষায় বাস্তবায়ন সহজে বদলাতে দেয়। মিডিয়ার সাথে কাজের জন্য Facade দেখি — লোডিং, ক্যাশিং এবং প্রদর্শন।
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 ImageCache, URLSession এবং ImageDecoder পরিচালনার পরিবর্তে একটি মাত্র মেথড loadImage(from:) কল করে। পরীক্ষার সময়, MediaServiceProtocol-কে প্রকৃত লোডিং ছাড়া পূর্বনির্ধারিত ছবি ফেরত দেওয়া mock দিয়ে প্রতিস্থাপন করা যায়।
ভুলগুলো Facade-এর ডিজাইনে তার সুবিধাগুলোকে বাতিল করে দেয়: সরলীকরণের পরিবর্তে আপনি God Object পান, যার উপর পুরো সিস্টেম নির্ভর করে। তিনটি প্রধান সমস্যা বিশ্লেষণ করি।
যখন একটি Facade-এ প্রমাণীকরণ, প্রোফাইল লোডিং, বার্তা পাঠানো এবং সিঙ্ক্রোনাইজেশনের মেথড থাকে — এটি একটি God Object। লক্ষণ: একটি ক্লাসে 15+ পাবলিক মেথড। সমাধান: দায়িত্বের ক্ষেত্র অনুযায়ী কয়েকটি বিশেষায়িত Facade-এ ভাগ করুন — AuthService, ProfileService, MessagingService।
যদি Facade সাবসিস্টেমের জন্য নির্দিষ্ট টাইপ ফেরত দেয় (উদাহরণস্বরূপ, FirebaseUser বা RealmObject), তাহলে ক্লায়েন্ট এখনও একটি নির্দিষ্ট বাস্তবায়নের সাথে বাঁধা থাকে। সমাধান: Facade-কে কেবল নিজস্ব টাইপ (data class / struct) ফেরত দিতে হবে, ক্লায়েন্টকে সাবসিস্টেমের বিবরণ থেকে সম্পূর্ণ বিমূর্ত করে।
যখন Facade সাবসিস্টেমে সরাসরি প্রবেশ নিষিদ্ধ করে, তখন এটি bottleneck হয়ে যায়। কখনো ক্লায়েন্টের সাবসিস্টেমের নির্দিষ্ট মেথড প্রয়োজন হয়, এবং তাকে Facade দিয়ে যেতে বাধ্য করা অপ্রয়োজনীয়। Facade-এর কঠোর গেটকিপার হওয়া উচিত নয়: এটি সুবিধাজনক ইন্টারফেস প্রদান করে, কিন্তু উপাদানে সরাসরি প্রবেশ আটকায় না।
সাধারণ জিজ্ঞাসা
Facade সাবসিস্টেমের জন্য একটি সরলীকৃত ইন্টারফেস প্রদান করে, প্রায়শই মেথডের নতুন সেট তৈরি করে। Proxy মূল বস্তুর মতো একই ইন্টারফেস বজায় রাখে, কিন্তু প্রবেশ নিয়ন্ত্রণ বা অলস লোডিং যোগ করে। Facade সরলীকরণের জন্য, Proxy নিয়ন্ত্রণের জন্য।
Service Layer অ্যাপ্লিকেশন আর্কিটেকচার স্তরে Facade প্যাটার্নের একটি বাস্তবায়ন। এটি UI এবং ব্যবসায়িক লজিকের মধ্যে সীমানা নির্ধারণ করে, পরিষেবার বাস্তবায়নের বিবরণ লুকিয়ে রাখে। Android-এ, Service Layer প্রায়শই UseCase-এর মাধ্যমে বাস্তবায়িত হয়; iOS-এ — Manager বা Service প্রোটোকলের মাধ্যমে।
God Facade তখন উত্থিত হয় যখন একটি ক্লাস বেশ কয়েকটি অসম্পর্কিত সাবসিস্টেমের দায়িত্ব নেয়। লক্ষণ: 15+ পাবলিক মেথড, বিভিন্ন ডোমেনের মেথড (প্রমাণীকরণ + পেমেন্ট + নোটিফিকেশন), একটি ক্লাস যা পরীক্ষা করা কঠিন (10+ নির্ভরতা)। সমাধান: ডোমেন Facade-এ ভাগ করুন।
1-2 স্ক্রিনের অ্যাপ্লিকেশনে Facade অপ্রয়োজনীয় — UI থেকে API এবং ডেটাবেস সরাসরি কল করা সহজ এবং পরিষ্কার। Facade ফল দেয় 5+ স্ক্রিন এবং 3+ সাবসিস্টেমে। ছোট ও মাঝারি প্রকল্পে একমাত্র Facade স্তর হিসেবে Repository যথেষ্ট, অতিরিক্ত UseCase আচ্ছাদন ছাড়া।
Facade পরীক্ষাকে সহজ করে, কারণ এটি পুরো সাবসিস্টেমকে একটি মাত্র mock বস্তু দিয়ে প্রতিস্থাপন করে। তিনটি উপাদান (নেটওয়ার্ক + ডেটাবেস + অ্যানালিটিক্স) mock করার পরিবর্তে একটি Facade mock করা যথেষ্ট। Swift-এ এর জন্য প্রোটোকল ব্যবহৃত হয়, Kotlin-এ — ইন্টারফেস। Facade ইন্টিগ্রেশন পরীক্ষার জন্যও সুবিধাজনক, যেখানে উপাদানের অর্কেস্ট্রেশন যাচাই করা হয়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন