نمط الاستراتيجية (Strategy Pattern)
جزء من قسم Object Oriented Programming في رحلة C# على Coddy — الدرس 55 من 70.
إن نمط الاستراتيجية (Strategy pattern) هو نمط سلوكي يتيح لك تعريف عائلة من الخوارزميات، وتغليف كل واحدة منها في فئة (class) خاصة بها، وجعلها قابلة للتبديل في وقت التشغيل (runtime). فبدلاً من كتابة السلوك برمجياً بشكل ثابت (hardcoding)، تقوم بحقن الاستراتيجية المطلوبة داخل كائن (object).
يتكون النمط من ثلاثة أجزاء: واجهة استراتيجية تحدد عقد الخوارزمية، وفئات استراتيجية ملموسة تنفذ سلوكيات مختلفة، وفئة سياق تستخدم استراتيجية:
public interface IPaymentStrategy
{
void Pay(decimal amount);
}
public class CreditCardPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via Credit Card");
}
public class PayPalPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via PayPal");
}
public class ShoppingCart
{
private IPaymentStrategy _paymentStrategy;
public void SetPaymentMethod(IPaymentStrategy strategy)
{
_paymentStrategy = strategy;
}
public void Checkout(decimal total)
{
_paymentStrategy.Pay(total);
}
}لا يعرف السياق (ShoppingCart) أي وسيلة دفع يستخدمها - هو فقط يستدعي Pay() على أي استراتيجية تم توفيرها:
var cart = new ShoppingCart();
cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m); // تم دفع 99.99 عبر بطاقة الائتمان
cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m); // تم دفع 49.99 عبر PayPalيقضي نمط الاستراتيجية (Strategy pattern) على المنطق الشرطي المعقد. إضافة وسيلة دفع جديدة تعني إنشاء فئة (class) جديدة تنفذ IPaymentStrategy - لا حاجة لإجراء تغييرات في ShoppingCart. هذا يجعل الكود الخاص بك مفتوحاً للتوسيع ولكن مغلقاً للتعديل.
التحدي
سهللنقم ببناء آلة حاسبة لتكلفة الشحن باستخدام نمط الاستراتيجية (Strategy pattern). طرق الشحن المختلفة لها خوارزميات تسعير مختلفة، ويجب أن يسمح نظامك بالتبديل بينها في وقت التشغيل دون تغيير منطق معالجة الطلبات الأساسي.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
ShippingStrategy.cs: قم بتعريف واجهةIShippingStrategyفي مساحة الأسماءShippingمع طريقةCalculateCost(double weight)التي ترجعdouble. ثم قم بإنشاء ثلاث فئات استراتيجية ملموسة:StandardShipping- تحسب التكلفة كـweight * 1.5ExpressShipping- تحسب التكلفة كـweight * 3.0 + 5.0(تتضمن رسوم شحن سريع ثابتة)OvernightShipping- تحسب التكلفة كـweight * 5.0 + 10.0(خدمة مميزة مع رسوم أساسية أعلى)
OrderProcessor.cs: قم بإنشاء فئةOrderProcessorفي نفس مساحة الأسماء. هذه هي فئة السياق (context class) التي تستخدم استراتيجية الشحن. يجب أن تحتوي على:- حقل خاص للاحتفاظ بـ
IShippingStrategyالحالي - طريقة
SetShippingMethod(IShippingStrategy strategy)لتغيير استراتيجية الشحن - طريقة
ProcessOrder(double weight)تستخدم الاستراتيجية الحالية لحساب وإرجاع تكلفة الشحن
- حقل خاص للاحتفاظ بـ
Program.cs: اجمع كل شيء معاً عن طريق إنشاءOrderProcessorوتوضيح كيف يمكنك تبديل استراتيجيات الشحن في وقت التشغيل. يمكن لنفس المعالج حساب التكاليف باستخدام خوارزميات مختلفة ببساطة عن طريق تغيير استراتيجيته.
ستتلقى مدخلين:
- نوع طريقة الشحن:
standard، أوexpress، أوovernight - وزن الطرد كرقم عشري (على سبيل المثال،
4.5)
قم بإنشاء OrderProcessor، وضبط استراتيجية الشحن المناسبة بناءً على نوع الإدخال، ثم قم بمعالجة الطلب واطبع التكلفة المحسوبة.
على سبيل المثال، إذا كانت المدخلات هي express و 4.5، فيجب أن يكون الناتج:
18.5يوضح هذا قوة نمط الاستراتيجية - حيث لا يحتوي OrderProcessor الخاص بك على أي منطق لحساب الشحن بنفسه. إنه ببساطة يفوض المهمة لأي استراتيجية تم إعطاؤها له، مما يجعل من السهل إضافة طرق شحن جديدة (مثل DroneDelivery) دون تعديل المعالج على الإطلاق!
ورقة مرجعية
إن نمط الاستراتيجية (Strategy pattern) هو نمط سلوكي يحدد عائلة من الخوارزميات، ويغلف كل واحدة منها في فئة (class) خاصة بها، ويجعلها قابلة للتبديل في وقت التشغيل.
يتكون النمط من ثلاثة أجزاء:
- واجهة الاستراتيجية (Strategy interface): تحدد عقد الخوارزمية
- فئات الاستراتيجية الملموسة (Concrete strategy classes): تنفذ سلوكيات مختلفة
- فئة السياق (Context class): تستخدم استراتيجية دون معرفة تفاصيل تنفيذها
هيكل المثال:
// واجهة الاستراتيجية
public interface IPaymentStrategy
{
void Pay(decimal amount);
}
// الاستراتيجيات الملموسة
public class CreditCardPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via Credit Card");
}
public class PayPalPayment : IPaymentStrategy
{
public void Pay(decimal amount) =>
Console.WriteLine($"Paid {amount} via PayPal");
}
// فئة السياق
public class ShoppingCart
{
private IPaymentStrategy _paymentStrategy;
public void SetPaymentMethod(IPaymentStrategy strategy)
{
_paymentStrategy = strategy;
}
public void Checkout(decimal total)
{
_paymentStrategy.Pay(total);
}
}الاستخدام - تبديل الاستراتيجيات في وقت التشغيل:
var cart = new ShoppingCart();
cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m); // Paid 99.99 via Credit Card
cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m); // Paid 49.99 via PayPalالفوائد:
- يلغي المنطق الشرطي المعقد
- مفتوح للتوسيع، مغلق للتعديل
- إضافة استراتيجيات جديدة تتطلب فقط إنشاء فئات جديدة، دون تغييرات في الكود الحالي
جرّب بنفسك
using System;
using Shipping;
class Program
{
public static void Main(string[] args)
{
// قراءة المدخلات
string shippingType = Console.ReadLine();
double weight = Convert.ToDouble(Console.ReadLine());
// TODO: إنشاء مثيل من OrderProcessor
// TODO: بناءً على shippingType ("standard" أو "express" أو "overnight")،
// إنشاء استراتيجية الشحن المناسبة وتعيينها في الـ processor
// TODO: معالجة الطلب وطباعة التكلفة المحسوبة
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةNamespaces والتوجيهاتمقدمة في Classes و Objectsالكلمة المفتاحية 'this'Methods والمعاملاتFields مقابل PropertiesConstructorsObject Initializersمراجعة - آلة حاسبة بسيطة4الوراثة
صيغة الوراثة الأساسية (:)الكلمة المفتاحية 'base'الكلمات المفتاحية Virtual و Overrideالأصناف المختومة (Sealed Classes)الفئة الأساسية 'object'مراجعة - هيكلية الموظفين7ميزات متقدمة
تحميل العوامل (Operator Overloading)المفهرسات (Indexers (this[]))إعادة تعريف ()ToStringدوال التوسعة (Extension Methods)ملخص - Custom List10أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singleton الآمن للخيوط (Thread-Safe)نمط المصنع (Factory Pattern)نمط المراقب (Events)نمط الاستراتيجية (Strategy Pattern)2الخصائص والأعضاء الساكنة (Static Members)
الخصائص المطبقة تلقائيًا (Auto-Implemented Properties)خصائص القراءة فقط والكتابة فقطالحقول والدوال الساكنة (Static)الفئات الساكنة (Static Classes)الأعضاء ذات البنية التعبيرية (Expression-Bodied Members)5تعدد الأشكال والواجهات (Polymorphism & Interfaces)
تعدد الأشكال: وقت التجميع مقابل وقت التشغيلالواجهة مقابل الفئة المجردة (Abstract Class)الواجهات المتعددةالواجهات الصريحةUpcasting و Downcastingملخص - حاسبة الأشكال8مفاهيم البرمجة كائنية التوجه (OOP) المتقدمة
التركيب بدلاً من الوراثةالـ Generics (الأصناف والدوال)الـ Delegates والأحداثالـ Attributes والـ Reflectionواجهة IDisposable وجملة usingأساسيات Dependency Injection