Strategy (اسٹریٹیجی) ایک رویاتی ڈیزائن پیٹرن ہے جو قابل تبادلہ الگورتھم کے ایک خاندان کی تعریف کرتا ہے اور ان میں سے ہر ایک کو علیحدہ کلاس (Strategy) میں رکھتا ہے۔ پیٹرن چلتے پھرتے الگورتھم منتخب کرنے کی اجازت دیتا ہے: کلائنٹ کوڈ ایک مشترکہ Strategy انٹرفیس کے ذریعے کام کرتا ہے، اور مخصوص نفاذ رن ٹائم میں تبدیل کیا جاتا ہے۔ iOS میں، پیٹرن کو Protocol + اسٹریٹیجی کلاسز کے ذریعے نافذ کیا جاتا ہے، Android میں — Interface + نفاذ کے ذریعے۔ Strategy 23 GoF پیٹرنز میں سے ایک ہے، جو ادائیگی کی پروسیسنگ، توثیق، ترتیب اور ڈیٹا فلٹرنگ کے لیے وسیع پیمانے پر استعمال ہوتا ہے۔ مزید تفصیل کے لیے — اصل GoF تفصیل دیکھیں۔
اہم نکات
Strategy 23 GoF (Gang of Four) پیٹرنز میں سے ایک ہے، جو "Design Patterns: Elements of Reusable Object-Oriented Software" (1994) کتاب میں بیان کیا گیا ہے۔ پیٹرن رن ٹائم پر الگورتھم منتخب کرنے کا مسئلہ حل کرتا ہے۔ متعدد شرطی بیانات (if-else, switch) والی ایک کلاس لکھنے کے بجائے، Strategy ہر الگورتھم کو ایک مشترکہ انٹرفیس کے ساتھ علیحدہ کلاس میں نکالنے کی تجویز کرتا ہے۔ سیاق و متن (وہ کلاس جو اسٹریٹیجی استعمال کرتی ہے) Strategy انٹرفیس کا حوالہ رکھتا ہے اور عملدرآمد ٹھوس اسٹریٹیجی کو سونپتا ہے۔
پیٹرن کی ساخت میں تین عناصر شامل ہیں: Context (سیاق و متن) Strategy کا حوالہ رکھتا ہے اور اس کا طریقہ کال کرتا ہے؛ Strategy (انٹرفیس) تمام الگورتھم کے لیے ایک مشترکہ طریقہ اعلان کرتا ہے؛ ConcreteStrategy (ٹھوس اسٹریٹیجی) انٹرفیس کو نافذ کرتی ہے اور ٹھوس الگورتھم رکھتی ہے۔ کلائنٹ مطلوبہ اسٹریٹیجی بناتا ہے اور اسے کنسٹرکٹر، سیٹر یا طریقہ پیرامیٹر کے ذریعے سیاق و متن میں دیتا ہے۔ سیاق و متن نہیں جانتا کہ کون سی مخصوص اسٹریٹیجی عمل میں ہے — یہ صرف انٹرفیس کے ساتھ کام کرتا ہے۔
| جزو | کردار | مثال |
|---|---|---|
| Context | Strategy کا حوالہ رکھتا ہے | PaymentProcessor, Sorter |
| Strategy | الگورتھم کے لیے مشترکہ انٹرفیس | Protocol PaymentStrategy |
| ConcreteStrategy | الگورتھم کا ٹھوس نفاذ | CardPayment, PayPalPayment |
Open/Closed اصول — Strategy کا بنیادی فائدہ۔ نظام توسیع کے لیے کھلا ہے (نئی اسٹریٹیجی شامل کی جا سکتی ہے) اور ترمیم کے لیے بند ہے (سیاق و متن کوڈ کو تبدیل کرنے کی ضرورت نہیں)۔ پیٹرن کے بغیر، نیا الگورتھم شامل کرنے کے لیے موجودہ کلاس کو تبدیل کرنا ضروری ہے، جو OCP کی خلاف ورزی کرتا ہے اور رجعت کی خرابیوں کا خطرہ بڑھاتا ہے۔ Strategy کلاس کے سائز کو بھی کم کرتا ہے: switch-case والی 200 سطروں والی کلاس کی بجائے، آپ کو 20 سطروں والی 6 کلاسیں ملتی ہیں۔
Swift میں Strategy کو Protocol (اسٹریٹیجی انٹرفیس) اور اسٹریٹیجی کلاسز یا ڈھانچوں کے ذریعے نافذ کیا جاتا ہے۔ Swift پروٹوکول متعلقہ اقسام اور عام رکاوٹوں کو سپورٹ کرتے ہیں، جو اسٹریٹیجی ڈیزائن کرتے وقت لچک فراہم کرتے ہیں۔ سیاق و متن عام طور پر ایک ViewModel کلاس یا سروس ہے جو init میں یا خاصیت کے ذریعے اسٹریٹیجی قبول کرتی ہے۔ پیٹرن iOS منصوبوں میں واقعہ ہینڈلنگ، اینیمیشن، ڈیٹا فارمیٹنگ اور UI اسٹریٹیجی کے لیے وسیع پیمانے پر استعمال ہوتا ہے۔
// 1. Protocol Strategy
protocol PaymentStrategy {
func pay(amount: Decimal) async throws -> PaymentResult
}
// 2. Concrete Strategies
struct CardPaymentStrategy: PaymentStrategy {
let cardNumber: String
let cvv: String
func pay(amount: Decimal) async throws -> PaymentResult {
// بینکنگ API کو درخواست بھیجنا
return PaymentResult(status: .success, transactionId: "tx_\(UUID())")
}
}
struct PayPalPaymentStrategy: PaymentStrategy {
let email: String
func pay(amount: Decimal) async throws -> PaymentResult {
// PayPal SDK پر ری ڈائریکٹ
return PaymentResult(status: .success, transactionId: "pp_\(UUID())")
}
}
// 3. Context
class PaymentProcessor {
private var strategy: PaymentStrategy
init(strategy: PaymentStrategy) {
self.strategy = strategy
}
func setStrategy(_: PaymentStrategy) {
strategy = strategy
}
func processPayment(amount: Decimal) async throws -> PaymentResult {
return try await strategy.pay(amount: amount)
}
}
// استعمال
let processor = PaymentProcessor(strategy: CardPaymentStrategy(cardNumber: "4111...", cvv: "123"))
let result = try await processor.processPayment(amount: 99.99)
SwiftUI میں Strategy — پیٹرن قدرتی طور پر MVVM کے ساتھ ضم ہوتا ہے۔ ViewModel میں ایک اسٹریٹیجی خاصیت ہوتی ہے اور صارف کے عمل پر اس کا طریقہ کال کرتا ہے۔ SwiftUI View @Published یا @State کے ذریعے ڈیٹا حاصل کرتی ہے — اسٹریٹیجی View سے نفاذ کی تفصیلات چھپاتی ہے۔ مثال کے طور پر، ٹیکسٹ توثیق اسٹریٹیجی (emailValidator, phoneValidator) ان پٹ فیلڈ کی قسم کے مطابق تبدیل کی جاتی ہے۔ Strategy کو SwiftUI کے ساتھ ملا کر UIKit سے وراثت حاصل کیے بغیر لچک ملتی ہے۔
Kotlin میں Strategy زبان کی سطح پر Interface استعمال کرتا ہے اور آسانی کے لیے فنکشنل انٹرفیس (SAM) استعمال کرتا ہے۔ Kotlin lambda کو سپورٹ کرتا ہے، جس سے علیحدہ اسٹریٹیجی کلاس اعلان کیے بغیر الگورتھم کو فنکشن کے طور پر منتقل کیا جا سکتا ہے۔ Android میں، پیٹرن ViewModel اور Use Cases میں ڈیٹا لوڈنگ، کیشنگ اور خرابی سے نمٹنے کے الگورتھم کو الگ کرنے کے لیے استعمال ہوتا ہے۔ Clean Architecture استعمال کرنے والے Android منصوبے جھنڈوں (mock, real, cache) کے مطابق مختلف ذخیرہ نفاذ انجیکٹ کرنے کے لیے Strategy استعمال کرتے ہیں۔
// 1. Interface Strategy
interface PaymentStrategy {
suspend fun pay(amount: BigDecimal): PaymentResult
}
// 2. Concrete Strategies
class CardPaymentStrategy(
private val cardNumber: String,
private val cvv: String
) : PaymentStrategy {
override suspend fun pay(amount: BigDecimal): PaymentResult {
// Retrofit کے ذریعے بینکنگ API
return PaymentResult(success = true, transactionId = "tx_${UUID.randomUUID()}")
}
}
class PayPalPaymentStrategy(
private val email: String
) : PaymentStrategy {
override suspend fun pay(amount: BigDecimal): PaymentResult {
// PayPal SDK انضمام
return PaymentResult(success = true, transactionId = "pp_${UUID.randomUUID()}")
}
}
// 3. Context
class PaymentProcessor(
private val strategy: PaymentStrategy
) {
fun setStrategy(strategy: PaymentStrategy): PaymentProcessor {
return PaymentProcessor(strategy)
}
suspend fun processPayment(amount: BigDecimal): PaymentResult {
return strategy.pay(amount)
}
}
// ViewModel میں استعمال
class CheckoutViewModel : ViewModel() {
private var processor = PaymentProcessor(CardPaymentStrategy("4111...", "123"))
fun payWithCard() {
viewModelScope.launch {
val result = processor.processPayment(BigDecimal("99.99"))
// نتیجہ کی پروسیسنگ
}
}
}
Hilt/Dagger کے ساتھ Strategy — Android منصوبوں میں، اسٹریٹیجی اکثر DI کے ذریعے انجیکٹ کی جاتی ہیں۔ Hilt @Binds یا @Provides کے ذریعے PaymentStrategy کا ٹھوس نفاذ فراہم کرتا ہے۔ یہ سیاق و متن کوڈ کو تبدیل کیے بغیر اسٹریٹیجی تبدیل کرنے کی اجازت دیتا ہے — دوسرے بلڈ (debug/release) کے لیے صرف DI ماڈیول تبدیل کریں۔ مثال کے طور پر، ڈیبگنگ کے لیے MockPaymentStrategy انجیکٹ کیا جاتا ہے، پروڈکشن کے لیے اصلی بینکنگ اسٹریٹیجی۔ Strategy + DI کا امتزاج زیادہ سے زیادہ لچک فراہم کرتا ہے۔
Strategy vs State — ساختی طور پر پیٹرن ایک جیسے ہیں: دونوں ایک انٹرفیس اور ٹھوس کلاسز کے ساتھ ترکیب استعمال کرتے ہیں۔ فرق مقصد میں ہے: Strategy ایک آزاد الگورتھم منتخب کرتا ہے، State اپنی حالت کے مطابق آبجیکٹ کے رویے کو کنٹرول کرتا ہے۔ State میں، سیاق و متن خود اسٹریٹیجی تبدیل کرتا ہے جب حالت بدلتی ہے؛ Strategy میں، سیاق و متن تبدیلی کو کنٹرول نہیں کرتا — کلائنٹ واضح طور پر الگورتھم سیٹ کرتا ہے۔ اسٹریٹیجی ایک دوسرے کے بارے میں نہیں جانتیں، جبکہ حالتیں ایک دوسرے میں منتقل ہو سکتی ہیں۔
Strategy vs Command — Command ایک ایکشن کو آبجیکٹ کے طور پر encapsulate کرتا ہے، Strategy قابل تبادلہ الگورتھم کے ایک سیٹ کو encapsulate کرتا ہے۔ Command "کیا کرنا ہے" (ایک execute کال)، Strategy "کیسے کرنا ہے" (کئی مراحل کا الگورتھم)۔ Command قطاروں، موخر عملدرآمد، کالعدم/دوبارہ کرنے کے لیے استعمال ہوتا ہے۔ Strategy رن ٹائم پر کام انجام دینے کا طریقہ منتخب کرنے کے لیے استعمال ہوتا ہے۔ کمانڈز کو Strategy کے ساتھ پیرامیٹرائز کیا جا سکتا ہے، دونوں پیٹرن کو ملا کر۔
| خصوصیت | Strategy | State | Command | Template Method |
|---|---|---|---|---|
| مقصد | قابل تبادلہ الگورتھم | حالت کے مطابق رویہ | درخواست encapsulation | الگورتھم کا ڈھانچہ |
| تبدیلی | کلائنٹ کے ذریعے واضح طور پر | سیاق و متن کے ذریعے خودکار | کلائنٹ یا قطار | وراثت سے |
| سطح | آبجیکٹ (ترکیب) | آبجیکٹ (ترکیب) | آبجیکٹ | کلاس (وراثت) |
Strategy vs Template Method — دونوں پیٹرن الگورتھم کی تعریف کرتے ہیں لیکن مختلف طریقوں سے۔ Template Method وراثت استعمال کرتا ہے: ایک بنیادی کلاس الگورتھم کا ڈھانچہ (ٹیمپلیٹ طریقہ) طے کرتی ہے، ذیلی کلاسیں انفرادی مراحل کو اوور رائڈ کرتی ہیں۔ Strategy ترکیب استعمال کرتا ہے: الگورتھم مکمل طور پر علیحدہ کلاس میں خارجی کیا جاتا ہے۔ Template Method مقررہ الگورتھم ساخت والے معاملات کے لیے آسان ہے، Strategy — جب الگورتھم مکمل طور پر مختلف ہوں اور متحرک طور پر تبدیل ہو سکیں۔
ادائیگی کی پروسیسنگ — Strategy کی کلاسک مثال۔ آن لائن اسٹور کی شاپنگ کارٹ میں اشیاء کی فہرست ہوتی ہے اور ادائیگی کا طریقہ صارف منتخب کرتا ہے۔ ہر طریقہ (کارڈ، PayPal، Apple Pay، Google Pay، کرپٹو کرنسی) مشترکہ pay(amount) دستخط کے ساتھ ایک علیحدہ اسٹریٹیجی ہے۔ PaymentProcessor سیاق و متن نہیں جانتا کہ ادائیگی کیسے پروسیس ہوتی ہے — یہ مشترکہ طریقہ کال کرتا ہے۔ نیا ادائیگی طریقہ شامل کرنے کے لیے کارٹ کوڈ تبدیل کرنے کی ضرورت نہیں۔
ڈیٹا کی توثیق — Strategy اسی فیلڈ کے مختلف توثیق کے اصولوں کے لیے استعمال ہوتا ہے۔ EmailValidatorStrategy، PhoneValidatorStrategy، AgeValidatorStrategy validate(input) طریقہ کے ساتھ مشترکہ ValidationStrategy انٹرفیس نافذ کرتی ہیں۔ رجسٹریشن فارم ہر فیلڈ کو جانچنے کے لیے اسٹریٹیجی کا ایک سیٹ استعمال کرتا ہے۔ توثیق کی اسٹریٹیجی کو ایک زنجیر (Chain of Responsibility) میں ملایا جا سکتا ہے یا ایک لوپ میں ایک ساتھ لاگو کیا جا سکتا ہے۔ یہ لمبی if-else جانچوں کو polymorphic توثیق کنندگان کے مجموعے سے بدل دیتا ہے۔
// ترتیب کی اسٹریٹیجی
protocol SortingStrategy {
func sort<T>(_ items: [T]) -> [T] where T: Comparable
}
struct QuickSortStrategy: SortingStrategy {
func sort<T>(_ items: [T]) -> [T] { /* quicksort */ items }
}
struct MergeSortStrategy: SortingStrategy {
func sort<T>(_ items: [T]) -> [T] { /* mergesort */ items }
}
class SortedDataSource<T> {
private var strategy: SortingStrategy
func display(_ items: [T]) { let sorted = strategy.sort(items) }
}
مصدقہ — موبائل ایپس میں، فراہم کنندہ کے مطابق مصدقہ اسٹریٹیجی تبدیل ہوتی ہیں۔ AuthStrategy login()، logout()، getToken() طریقوں کے ساتھ EmailPasswordAuth، GoogleAuth، AppleAuth، BiometricAuth کے لیے نافذ کیا جاتا ہے۔ AuthManager سیاق و متن DI یا فیکٹری کے ذریعے اسٹریٹیجی قبول کرتا ہے۔ یہ لاگ ان اسکرین کو تبدیل کیے بغیر نئے مصدقہ فراہم کنندگان شامل کرنے کی اجازت دیتا ہے۔ Strategy پیٹرن بہت سی OAuth لائبریریوں اور Firebase Authentication کی بنیاد ہے۔
اکثر پوچھے گئے سوالات
Strategy درست ہے جب آپ کے پاس 3+ الگورتھم ہوں جو تبدیل یا پھیل سکتے ہیں۔ اگر 2 الگورتھم ہیں اور وہ مستحکم ہیں — سادہ if-else کم خرچ ہے۔ Strategy استعمال کریں جب الگورتھم ایپلیکیشن کے مختلف حصوں میں استعمال ہوں، جب آپ کو رن ٹائم پر الگورتھم تبدیل کرنے کی ضرورت ہو، یا جب ہر الگورتھم کو اپنی انحصار اور ٹیسٹ کی ضرورت ہو۔
نہیں، یہ مختلف پیٹرن ہیں جن کی ساخت ایک جیسی ہے۔ Strategy — کلائنٹ واضح طور پر الگورتھم منتخب کرتا ہے اور اسٹریٹیجی آزاد ہیں۔ State — جب اس کی داخلی حالت بدلتی ہے تو آبجیکٹ خود اپنا رویہ بدلتا ہے اور حالتیں ایک دوسرے میں منتقل ہو سکتی ہیں۔ State میں، سیاق و متن حالت کی تبدیلی کا انتظام کرتا ہے؛ Strategy میں، کلائنٹ کوڈ یہ کرتا ہے۔
ہاں، Swift اور Kotlin میں اسٹریٹیجی کو closure یا lambda کے طور پر منتقل کیا جا سکتا ہے۔ Swift: typealias PaymentHandler = (Decimal) async throws -> PaymentResult. Kotlin: typealias PaymentFun = suspend (BigDecimal) -> PaymentResult. یہ سادہ معاملات کے لیے کوڈ آسان بناتا ہے لیکن نام بندی اور دستاویزات کھو دیتا ہے۔ 1-2 الگورتھم کے لیے، closure کافی ہے؛ 4+ کے لیے، علیحدہ کلاسیں بہتر ہیں۔
ہر اسٹریٹیجی کو فرضی انحصار کے ساتھ علیحدہ یونٹ ٹیسٹ سے جانچا جاتا ہے۔ سیاق و متن کو فرضی اسٹریٹیجی سے جانچا جاتا ہے — تصدیق کرتے ہوئے کہ سیاق و متن اسٹریٹیجی کا طریقہ کال کرتا ہے اور صحیح پیرامیٹر منتقل کرتا ہے۔ Swift میں، فرضی کے لیے XCTest + پروٹوکول استعمال کریں؛ Kotlin میں، MockK یا Mockito استعمال کریں۔ بنیادی فائدہ: ہر اسٹریٹیجی پیچیدہ سیٹ اپ کے بغیر الگ تھلگ جانچی جاتی ہے۔
ہاں، Strategy ان 23 پیٹرنز میں سے ایک ہے جو "Design Patterns: Elements of Reusable Object-Oriented Software" (Gamma, Helm, Johnson, Vlissides, 1994) کتاب میں بیان کیے گئے ہیں۔ یہ رویاتی پیٹرن کے گروپ سے تعلق رکھتا ہے۔ متبادل نام: Policy۔ Smalltalk-80 میں اصل مثال کوڈ GoF کے اصل ایڈیشن میں دستیاب ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں