Strategy Pattern خبير الاستراتيجيات الذكي
السلام عليكم ورحمة الله وبركاته
المقدمة
اليوم سنتعلم كيف نصمم نظامًا ذكيًا يتكيف مع التغييرات بسهولة وسلاسة دون الحاجة لتعديل الكود الأساسي بشكل متكرر
وسنفعل ذلك باستخدام الـ Strategy Pattern
وهو أحد الـ Design Patterns
وهو يندرج تحت عائلة الـ Behavioral Design Patterns
والـ Behavioral Design Patterns
بشكل عام تهتم بكيفية تفاعل الكلاسات مع بعضها البعض وكيفية تبادل البيانات بينها بشكل سلس
والـ Strategy Pattern
هوأحد تلك الطرق التي تساعدنا على تحقيق ذلك
في هذا المقال، سنستعرض كيف يمكننا استخدام الـ Strategy Pattern
لجعل تطبيقاتنا أكثر مرونة وقابلية للتوسع
والـ Strategy Pattern
يساعدنا على الاختيار والتبديل السلس بين الخوارزميات سواء كانت في الدوال أو الكلاسات المختلفة في اثناء الـ Runtime
وسنرى هذا في الأمثلة العملية التي سنقوم بها في هذا المقال
لكن بالطبع قبل أن نبدأ في شرح الـ Strategy Pattern
، دعونا نتعرف على المشكلة التي يقوم بحلها
المشكلة التي يحلها الـ Strategy Pattern
تخيل أنك مطالب بارسال بعض التقارير عن النظام
وكل تقرير يقوم بارسال بيانات مختلفة واحصائيات مختلفة
فقد يكون لديك تقارير مثل:
- تقرير عن المبيعات الشهرية
- تقرير عن الزبائن الجدد
- تقرير عن المنتجات الأكثر مبيعًا
- تقرير عن الشحنات المتأخرة
- تقرير عن الشحنات التي تم تسليمها
- تقرير عن الشحنات التي لم يتم تسليمها
- تقرير عن الشحنات التي تم إلغاؤها
- ... إلخ
تقارير كثيرة وكل تقرير له طريقة مختلفة في جمع البيانات وحسابها بشكل مختلف
فقد يكون لديك كلاس يدير عملية جمع البيانات، ستسميه ReportGenerator
والذي سيحتوي على دالة generate
التي تأخذ نوع التقرير
class ReportGenerator {
generate(reportType: string): void {
if (reportType === 'monthlySales') {
// جلب بيانات المبيعات من قاعدة البيانات
// حساب إجمالي المبيعات والأرباح
// إنشاء التقرير وعرضه
} else if (reportType === 'newCustomers') {
// جلب بيانات الزبائن الجدد من قاعدة البيانات
// حساب عدد الزبائن الجدد في الشهر
// إنشاء التقرير وعرضه
} else if (reportType === 'mostSoldProducts') {
// جلب بيانات المبيعات لكل منتج
// ترتيب المنتجات حسب كمية المبيعات
// إنشاء تقرير بالمنتجات الأكثر مبيعًا
} else if (reportType === 'delayedShipments') {
// جمع بيانات الشحنات المتأخرة
// تحليل أسباب التأخير
// إنشاء تقرير بالإجراءات المطلوبة
} else if (reportType === 'deliveredShipments') {
// جمع بيانات الشحنات التي تم تسليمها
// حساب نسبة الشحنات التي تم تسليمها بنجاح
// إنشاء تقرير بالشحنات التي تم تسليمها
} else if (reportType === 'undeliveredShipments') {
// جمع بيانات الشحنات التي لم يتم تسليمها
// تحليل أسباب عدم التسليم
// إنشاء تقرير بالشحنات التي لم يتم تسليمها
} else if (reportType === 'canceledShipments') {
// جمع بيانات الشحنات التي تم إلغاؤها
// تحليل أسباب الإلغاء
// إنشاء تقرير بالشحنات التي تم إلغاؤها
} else {
throw new Error('Invalid report type');
}
}
}
هل يمكنك تخيل المشاكل التي ستواجهها هنا؟
أولًا ستقول لي أن هناك الكثير من الأكواد المختلفة في دالة واحدة وهذاالكثير من المباديء البرمجية
مثل مبدأ Single Responsibility Principle
الذي ينص على أن كل كلاس أو دالة يجب أن تكون مسؤولة عن شيء واحد فقط
أما هنا سترى أن عدة عمليات مختلفة عن بعضها البعض مثل generate monthly sales
و generate new customers
و generate most sold products
كلها موجودة في دالة واحدة وهذا يتعارض مع مبدأ Single Responsibility Principle
وأيضًا الدالة تتعارض مع مبدأ Open/Closed Principle
الذي ينص على أن الكلاسات يجب أن تكون مفتوحة للتوسع ومغلقة للتعديل
أما هنا فكل شيء في دالة واحدة وفي كلاس واحد
فلو أردنا إضافة أو حذف أو تعديل أي تقرير، سنضطر لتعديل الدالة generate
في كل مرة
والدالة generate
ستصبح أكبر وأكبر مع مرور لذا التعديل فيها سيصبح صعبًا جدًا لأن هناك الكثير من الأكواد المختلفة والمتداخلة في دالة واحدة
وتعديل شيء واحد قد يجعلك دون قصد تفسد شيء آخر، فبدلًا من أن تعدل تقرير واحد ستجد نفسك قد أفسدت أكواد أخرى في التقارير الأخرى دون أن تدري
يمكننا ان نلخص المشاكل التي سنواجهها في النقاط التالية:
- عدم الالتزام بمبدأ
Single Responsibility Principle
بحيث أن الدالةgenerate
تقوم بكل شيء من جلب بيانات وتمعالجتها وعرضها وتقوم بهذا لعدة تقارير مختلفة - عدم الالتزام بمبدأ
Open/Closed Principle
بحيث أنك تضطر لتعديل الدالةgenerate
في كل مرة تريد فيها إضافة أو حذف أو تعديل أي تقرير - زيادة تعقيد الدالة
generate
مع مرور الوقت، مما يجعل من الصعب فهمها وتعديلها - زيادة فرص حدوث الأخطاء، حيث أن أي تعديل في الدالة
generate
قد يؤثر على التقارير الأخرى دون قصد - ... إلخ
هنا بالطبع لا داعي لأن أخبركم أن من سيحل هذه المشكلة هو بالطبع بطلنا المغوار وخبير الاستراتيجيات الذكي الـ Strategy Pattern
الذي سيساعدنا على فصل كل خوارزمية أو سلوك مختلف في كلاس منفصل، مما يجعل من السهل علينا إضافة أو حذف أو تعديل أي خوارزمية دون التأثير على الكلاسات الأخرى، وهو يعد تطبيق عملي ومباشر لمبدأ Open/Closed Principle
بطبع كل مباديء الـ SOLID
شرحناها في مقالة مبادئ الـ SOLID لجعل كودك صلب كالحديد
شرحنا فيها كل مبدأ من مباديء الـ SOLID
وكيفية تطبيقه في الكود بأمثلة عملية
ما هو الـ Strategy Pattern ؟
هو ببساطة طريقة لتقسيم الخوارزميات والأكواد المختلفة في كلاسات منفصلة، بحيث يمكننا استبدالها والتبديل بين تلك الخوارزميات بسهولة ودون الحاجة لتعديل الكود الأساسي
وهو ببساطة يتكون من 3
مكونات رئيسية:
Strategy Interface
: الـInterface
الأساسي الذي سيكون الشكل العام لكل كلاس من الاستراتيجيات المختلفة
وفي حالتنا سيكون لديناReportStrategy
الذي سيحتوي على دالةgenerate
التي ستقوم بجلب البيانات ومعالجتها وعرضها
أو يمكننا أن نقسمها إلى3
دوال مختلفة، بحيث تكون لدينا دالةfetchData
لجلب البيانات ودالةprocessData
لمعالجة البيانات ودالةdisplayData
لعرض البيانات
ويمكننا جعل الدالةgenerate
تقوم باستدعاء تلك الدوال الثلاثة على التواليConcrete Strategies
: الكلاسات التي تنفذ الـInterface
وتقوم بتطبيق الخوارزمية المختلفة
وفي حالتنا كل كلاس سيهتم بتنفيذ عملية واحدة، بالتالي سيكون لدينا:NewCustomersReportStrategy
MonthlySalesReportStrategy
MostSoldProductsReportStrategy
DelayedShipmentsReportStrategy
DeliveredShipmentsReportStrategy
- ... إلخ
وكل كلاس سيقوم بتنفيذ دالة
generate
الخاصة به والتي ستقوم بجلب البيانات ومعالجتها وعرضها
Context
: الكلاس الذي يستخدم الاستراتيجية المختارة
وهو الكلاس الأساسي الذي سيختار الاستراتيجية المناسبة ويقوم باستدعاء الدالةgenerate
الخاصة
ويستطيع التبديل بين الاستراتيجيات المختلفة في أي وقت، مما يجعل من السهل علينا إضافة أو حذف أو تعديل أي استراتيجية دون التأثير على الكلاسات الأخرى
التطبيق العملي للـ Strategy Pattern
الآن بعد أن فهمنا المكونات الأساسية للـ Strategy Pattern
، دعونا نطبقها على مثال التقارير الذي ذكرناه سابقًا
إنشاء الـ Strategy Interface
أولًا سنقوم بإنشاء الـ Interface
الأساسي الذي ستنفذه كل الاستراتيجيات الخاصة بالتقارير
لنسميه IReportStrategy
، وهو سيكون الشكل العام لكل كلاس من الاستراتيجيات المختلفة الخاصة بكل تقرير
interface IReportStrategy {
generate(): void;
}
هنا قمنا بعمل interface
بسيط يحتوي على دالة generate
فقط للتبسيط، لكن يمكنك تقسيمها إلى عدة دوال كما ذكرنا سابقًا
فيمكنك جعلها تحتوي على دالة fetchData
لجلب البيانات ودالة processData
لمعالجة البيانات ودالة displayData
لعرض البيانات
لكن من أجل التبسيط، سنتركها كما هي الآن تحتوي على دالة generate
فقط
إنشاء الـ Concrete Strategies
الآن سنقوم بإنشاء الكلاسات التي تنفذ الـ Interface
وكل كلاس سيهتم بنوع تقرير معين
والكلاسات التي ستنفذ الـ IReportStrategy
نسميها Concrete Strategies
ومن ضمن الكلاسات التي سنقوم بإنشائها هي هي NewCustomersReportStrategy
و MonthlySalesReportStrategy
و MostSoldProductsReportStrategy
و DelayedShipmentsReportStrategy
وغيرها حسب الحاجة
class NewCustomersReportStrategy implements IReportStrategy {
public generate(): void {
console.log('جاري جمع بيانات العملاء الجدد...');
// جلب بيانات العملاء الجدد من قاعدة البيانات
// معالجة البيانات وحساب الإحصائيات
// عرض التقرير أو إرساله
console.log('تم إنشاء تقرير العملاء الجدد بنجاح');
}
}
class MonthlySalesReportStrategy implements IReportStrategy {
public generate(): void {
console.log('جاري جمع بيانات المبيعات الشهرية...');
// جلب بيانات المبيعات من قاعدة البيانات
// حساب إجمالي المبيعات والأرباح
// إنشاء المخططات والرسوم البيانية
console.log('تم إنشاء تقرير المبيعات الشهرية بنجاح');
}
}
class MostSoldProductsReportStrategy implements IReportStrategy {
public generate(): void {
console.log('جاري تحليل بيانات المنتجات الأكثر مبيعًا...');
// جلب بيانات المبيعات لكل منتج
// ترتيب المنتجات حسب كمية المبيعات
// إنشاء قائمة بالمنتجات الأكثر مبيعًا
console.log('تم إنشاء تقرير المنتجات الأكثر مبيعًا بنجاح');
}
}
class DelayedShipmentsReportStrategy implements IReportStrategy {
public generate(): void {
console.log('جاري تحليل بيانات الشحنات المتأخرة...');
// جلب بيانات الشحنات المتأخرة
// تحليل أسباب التأخير
// إنشاء تقرير بالإجراءات المطلوبة
console.log('تم إنشاء تقرير الشحنات المتأخرة بنجاح');
}
}
لاحظ أن كل كلاس يركز على مهمة واحدة فقط وهي إنشاء نوع معين من التقارير
وكل كلاس يحتوي على المنطق والكود الخاص به لجمع ومعالجة وعرض البيانات
وهذا يتماشى مع مبدأ Single Responsibility Principle
حيث أن كل كلاس مسؤول عن شيء واحد فقط
وأيضًا يتماشى مع مبدأ Open/Closed Principle
حيث يمكنك إضافة كلاس جديد لتقرير جديد وجعله ينفذ IReportStrategy
دون الحاجة لتعديل الكود الموجود
إنشاء الـ Context
الآن سنقوم بإنشاء الكلاس الذي سيستخدم الاستراتيجيات المختلفة وهذا الكلام يسمى Context
وهو الكلاس الاساسي الذي سيختار الاستراتيجية المناسبة ويقوم باستدعاء الدالة generate
الخاصة بها
لنسميه ReportGenerator
، وهو سيكون الكلاس الذي يدير عملية إنشاء التقارير
ويحتوي على دالة setStrategy
لتغيير الاستراتيجية في أي وقت
ودالة generateReport
التي تستدعي الدالة generate
من الاستراتيجية الحالية
class ReportGenerator {
private strategy: IReportStrategy;
constructor(strategy: IReportStrategy) {
this.strategy = strategy;
}
public setStrategy(strategy: IReportStrategy): void {
this.strategy = strategy;
}
public generateReport(): void {
this.strategy.generate();
}
}
هنا قمنا بإنشاء كلاس ReportGenerator
الذي ستلاحظ عدة أشياء مهمة فيه:
- يحتوي على
strategy
من نوعIReportStrategy
- هنا سنستخدمه ونستفيد من فكرة الـ
Polymorphism
حيث أن كل كلاس من الاستراتيجيات المختلفة ينفذ نفس الـInterface
لذا فالمتغيرstrategy
يمكن أن يكون من أي نوع من الاستراتيجيات التي تنفذIReportStrategy
ولاحظ أننا هنا نتعامل معinterface
وهوIReportStrategy
ولا نهتم بنوع الاستراتيجية المستخدمة حاليًا وهذا هو مفهوم الـAbstracting
- هنا سنستخدمه ونستفيد من فكرة الـ
- يمكنه استقبال الاستراتيجية من خلال الـ
constructor
لتحديد الاستراتيجية الافتراضية عند إنشاءobject
منReportGenerator
لكن يمكننا أيضًا تغييرها لاحقًا - يحتوي على دالة
setStrategy
لتغيير الاستراتيجية في أي وقت وهنا تكمن المرونة في استخدام الـStrategy Pattern
حيث يمكنك تغيير الاستراتيجية في أي وقت حسب الحاجة - يحتوي على دالة
generateReport
التي تستدعي الدالةgenerate
من الاستراتيجية الحالية وبما أن كل الاستراتيجيات تنفذ نفس الـInterface
، فيمكننا استدعاءgenerate
دون الحاجة لمعرفة نوع الاستراتيجية المستخدمة حاليًا
استخدام الـ Strategy Pattern
الآن يمكننا استخدام الـ Strategy Pattern
بسهولة
// إنشاء تقرير العملاء الجدد
const newCustomersStrategy = new NewCustomersReportStrategy();
const reportGenerator = new ReportGenerator(newCustomersStrategy);
reportGenerator.generateReport();
// تغيير الاستراتيجية لإنشاء تقرير المبيعات الشهرية
const monthlySalesStrategy = new MonthlySalesReportStrategy();
reportGenerator.setStrategy(monthlySalesStrategy);
reportGenerator.generateReport();
// تغيير الاستراتيجية لإنشاء تقرير المنتجات الأكثر مبيعًا
const mostSoldProductsStrategy = new MostSoldProductsReportStrategy();
reportGenerator.setStrategy(mostSoldProductsStrategy);
reportGenerator.generateReport();
// تغيير الاستراتيجية لإنشاء تقرير الشحنات المتأخرة
const delayedShipmentsStrategy = new DelayedShipmentsReportStrategy();
reportGenerator.setStrategy(delayedShipmentsStrategy);
reportGenerator.generateReport();
هنا قمنا بإنشاء ReportGenerator
مع استراتيجية NewCustomersReportStrategy
، ثم قمنا بتوليد التقرير الخاص بالعملاء الجدد
ثم لاحقًا قمنا بتغيير الاستراتيجية إلى MonthlySalesReportStrategy
وتوليد تقرير المبيعات الشهرية
ثم قمنا بتغيير الاستراتيجية مرة أخرى إلى MostSoldProductsReportStrategy
وتوليد تقرير المنتجات الأكثر مبيعًا
شكل آخر للـ Context
يمكنك أيضًا استخدام دالة بسيطة كـ Context
بدلًا من كلاس
فالـ Context
ليس شرطًا أن يكون كلاس، بل يمكن أن يكون دالة بسيطة تقوم بأخذ enum
يمثل نوع التقرير وتقوم بتحديد الاستراتيجية المناسبة بناءً على ذلك
enum ReportType {
NewCustomers,
MonthlySales,
MostSoldProducts,
DelayedShipments,
}
function generateReport(reportType: ReportType): void {
let strategy: IReportStrategy;
switch (reportType) {
case ReportType.NewCustomers:
strategy = new NewCustomersReportStrategy();
break;
case ReportType.MonthlySales:
strategy = new MonthlySalesReportStrategy();
break;
case ReportType.MostSoldProducts:
strategy = new MostSoldProductsReportStrategy();
break;
case ReportType.DelayedShipments:
strategy = new DelayedShipmentsReportStrategy();
break;
default:
throw new Error('نوع التقرير غير مدعوم');
}
strategy.generate();
}
هنا قمنا بإنشاء دالة generateReport
التي تأخذ enum
يمثل نوع التقرير وتقوم بتحديد الاستراتيجية المناسبة بناءً على ذلك
داخل الدالة لدينا switch-case
يحدد أي استراتيجية يجب استخدامها بناءً على نوع التقرير المرسل
ثم ببساطة نستدعي الدالة generate
من الاستراتيجية المحددة
وطريقة الاستخدام ستكون كالتالي:
// استخدام الدالة لتوليد تقرير العملاء الجدد
generateReport(ReportType.NewCustomers);
// استخدام الدالة لتوليد تقرير المبيعات الشهرية
generateReport(ReportType.MonthlySales);
// استخدام الدالة لتوليد تقرير المنتجات الأكثر مبيعًا
generateReport(ReportType.MostSoldProducts);
// استخدام الدالة لتوليد تقرير الشحنات المتأخرة
generateReport(ReportType.DelayedShipments);
بهذه الطريقة، يمكنك استخدام الـ Strategy Pattern
لجعل الكود أكثر مرونة وقابلية للتوسع
ويمكنك بسهولة إضافة تقارير جديدة دون الحاجة لتعديل الكود الموجود، فقط قم بإنشاء كلاس جديد ينفذ IReportStrategy
ثم قم بتحديد الاستراتيجية الجديدة في الدالة generateReport
أو في كلاس ReportGenerator
يحسب الحاجة
فوائد الـ Strategy Pattern
دعونا نتذكر سريعًا الفوائد التي نحصل عليها من استخدام الـ Strategy Pattern
في مثال التقارير الذي قمنا به:
تطبيق مبدأ Single Responsibility Principle
كل كلاس أصبح مسؤولًا عن شيء واحد فقط:
NewCustomersReportStrategy
مسؤول فقط عن تقارير العملاء الجددMonthlySalesReportStrategy
مسؤول فقط عن تقارير المبيعات الشهريةReportGenerator
مسؤول فقط عن إدارة الاستراتيجيات واستدعائها- ... إلخ
بالتالي عندما تريد تعديل تقرير معين، يمكنك الذهاب مباشرة إلى الكلاس الخاص به وتعديله دون الحاجة للقلق بشأن تأثير ذلك على التقارير الأخرى
وهذا يجعل الكود أكثر وضوحًا وسهولة في الفهم والتعديل وكل الكلمات الرنانة التي نسمعها
تطبيق مبدأ Open/Closed Principle
الكود أصبح:
- مفتوحًا للتوسع: يمكنك إضافة أنواع جديدة من التقارير بعمل كلاس جديد ينفذ
ReportStrategy
- مغلقًا للتعديل: لا تحتاج لتعديل الكود الموجود عند إضافة تقارير جديدة، فمثلا لن تقوم بتعديل كلاس
ReportGenerator
أو الـIReportStrategy
أو حتى الكلاسات الأخرى
بل فقط تضيف كلاس جديد للتقرير الجديد وتجعله ينفذIReportStrategy
// إضافة تقرير جديد بدون تعديل أي كود موجود
class InventoryReportStrategy implements ReportStrategy {
public generate(): void {
console.log('جاري تحليل بيانات المخزون...');
// الكود الخاص بالتقرير الجديد
console.log('تم إنشاء تقرير المخزون بنجاح');
}
}
// استخدام التقرير الجديد
reportGenerator.setStrategy(new InventoryReportStrategy());
reportGenerator.generateReport();
سهولة التبديل بين الاستراتيجيات
يمكن تغيير الاستراتيجية في أي وقت حسب الحاجة
باستخدام دالة setStrategy
في كلاس ReportGenerator
، يمكنك التبديل بين الاستراتيجيات المختلفة بسهولة ودون الحاجة لتعديل الكود الأساسي
وهذا يجعل الكود أكثر مرونة وقابلية للتوسع
const reportGenerator = new ReportGenerator(
new MonthlySalesReportStrategy()
);
// توليد تقرير المبيعات الشهرية
reportGenerator.generateReport();
// تغيير الاستراتيجية إلى تقرير جديد
reportGenerator.setStrategy(new NewCustomersReportStrategy());
reportGenerator.generateReport();
// تغيير الاستراتيجية إلى تقرير آخر
reportGenerator.setStrategy(new MostSoldProductsReportStrategy());
reportGenerator.generateReport();
// تغيير الاستراتيجية إلى تقرير آخر
reportGenerator.setStrategy(new DelayedShipmentsReportStrategy());
reportGenerator.generateReport();
لكن الشيء السلبي هنا في استخدام كلاس ReportGenerator
هو أنك مجبر على انك وضع استراتيجية افتراضية عند إنشاء object
من ReportGenerator
لأول مرة
لأنك قد لا تحتاج إلى استراتيجية افتراضية في بعض الحالات خصوصًا لو كانت التقارير تعتمد على بيانات تلقيها من المستخدم أو من مصدر خارجي
لكن في هذه الحالة يمكنك استخدام الدالة generateReport
التي قمنا بإنشائها سابقًا والتي تأخذ enum
يمثل نوع التقرير وتقوم بتحديد الاستراتيجية المناسبة بناءً على ذلك بشكل ديناميكي
أول يمكنك ازالة الـ constructor
من كلاس ReportGenerator
وجعل الدالة setStrategy
هي المسؤولة عن تعيين الاستراتيجية الحالية
وفي حالة أنك لم تقم بتعيين استراتيجية، يمكنك جعلها ترمي exception
عند استدعاء generateReport
أو تعيين استراتيجية افتراضية مثل DefaultReportStrategy
التي تقوم بعرض رسالة تفيد بعدم تعيين استراتيجية
class ReportGenerator {
private strategy: IReportStrategy | null = null;
public setStrategy(strategy: IReportStrategy): void {
this.strategy = strategy;
}
public generateReport(): void {
if (!this.strategy) {
throw new Error('لم يتم تعيين استراتيجية للتقرير'); // أو يمكنك تعيين استراتيجية افتراضية هنا
}
this.strategy.generate();
}
}
الختام
الـ Strategy Pattern
يعد من أقوى الـ Design Patterns
التي تساعدك على كتابة كود سلس ومرن وقابل للتوسع بشكل كبير دون مشاكل أو تعقيدات
فهو يمكنك من:
- فصل الخوارزميات المختلفة في كلاسات منفصلة وهذا يتماشى مع مبدأ
Single Responsibility Principle
- التبديل بين الخوارزميات أثناء الـ
Runtime
بسهولة وهو تطبيق مباشر لفكرة الـPolymorphism
و الـAbstracting
- إضافة خوارزميات جديدة بدون تعديل الكود الموجود لأنه يطبق مبدأ
Open/Closed Principle
كما رأينا في هذا المقال، الـ Strategy Pattern
هو حل عملي لمشاكل حقيقية نواجهها في البرمجة بشكل يومي
فبدلًا من كتابة دوال طويلة مليئة بالـ if-else
أو switch-case
، يمكننا تنظيم الكود بطريقة أكثر احترافية ومرونة
أنصحك بتطبيق الـ Strategy Pattern
في مشاريعك القادمة، وخصوصًا في الأجزاء التي تحتاج منك لتطبيق كود مختلف بحسب status
أو action
أو type
معين
وستلاحظ كم سيصبح الكود أكثر سهولة في الفهم والتعديل وكل الكلام الرنان
وتذكر أن الهدف ليس استخدام الـ Design Patterns
لمجرد الاستخدام، بل لحل المشاكل الفعلية وتحسين جودة الكود
لأنه أحيانًا قد يكون استخدام الـ Design Patterns
غير ضروري أو حتى مضر إذا لم يكن هناك حاجة فعلية له وهذا حصل معي في بعض المشاريع التي عملت عليها
أتمنى أن يكون هذا المقال قد أعطى فكرة واضحة عن الـ Strategy Pattern
وكيفية استخدامه في البرمجة