نمط الاستراتيجية (Strategy Pattern)
جزء من قسم البرمجة كائنية التوجه في رحلة C# على Coddy. الدرس 55 من 70.
نمط Strategy pattern هو نمط سلوكي يتيح لك تعريف عائلة من الخوارزميات، وتغليف كل خوارزمية منها في فئتها الخاصة، وجعلها قابلة للتبديل أثناء التشغيل. وبدلًا من ترميز السلوك بشكل ثابت، تحقن الاستراتيجية المطلوبة في كائن.
يتكوّن النمط من ثلاثة أجزاء: واجهة strategy تحدد عقد الخوارزمية، وclassات strategy ملموسة تنفّذ سلوكيات مختلفة، وclass سياق يستخدم strategy:
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يلغي نمط الاستراتيجية المنطق الشرطي المعقد. تعني إضافة طريقة دفع جديدة إنشاء فئة جديدة تنفّذ IPaymentStrategy - ولا حاجة إلى إجراء أي تغييرات في ShoppingCart. وهذا يجعل كودك مفتوحًا للتوسعة لكنه مغلقًا أمام التعديل.
التحدي
سهللنبنِ حاسبة لتكلفة الشحن باستخدام نمط Strategy. تمتلك طرق الشحن المختلفة خوارزميات تسعير مختلفة، وينبغي أن يتيح نظامك التبديل بينها أثناء التشغيل دون تغيير منطق معالجة الطلب الأساسي.
ستنظّم كودك عبر ثلاثة ملفات:
ShippingStrategy.cs: Define واجهةIShippingStrategyفي مساحة الأسماءShippingمع methodCalculateCost(double weight)تُرجع قيمة من النوعdouble. ثم أنشئ ثلاث فئات استراتيجية Concrete:StandardShipping- تحسب cost وفقًا للمعادلةweight * 1.5ExpressShipping- تحسب cost وفقًا للمعادلةweight * 3.0 + 5.0(وتتضمن رسومًا ثابتة للشحن السريع)OvernightShipping- تحسب cost وفقًا للمعادلةweight * 5.0 + 10.0(خدمة متميزة برسوم أساسية أعلى)
OrderProcessor.cs: Create فئةOrderProcessorفي مساحة الأسماء نفسها. هذه هي فئة Context التي تستخدم استراتيجية شحن. ينبغي أن تحتوي على:- field خاص للاحتفاظ بـ
IShippingStrategyالحالية - method
SetShippingMethod(IShippingStrategy strategy)لتغيير استراتيجية الشحن - method
ProcessOrder(double weight)التي تستخدم الاستراتيجية الحالية لحساب تكلفة الشحن وإرجاعها
- field خاص للاحتفاظ بـ
Program.cs: اجمع كل شيء معًا من خلال إنشاءOrderProcessorوتوضيح كيفية تبديل استراتيجيات الشحن أثناء التشغيل. يمكن للمعالج نفسه حساب التكاليف باستخدام خوارزميات مختلفة بمجرد تغيير استراتيجيته.
ستتلقى مدخلين:
- نوع طريقة الشحن:
standardأوexpressأوovernight - وزن الطرد كرقم عشري (مثلًا:
4.5)
أنشئ OrderProcessor، واضبط استراتيجية الشحن appropriate استنادًا إلى نوع الإدخال، ثم عالج الطلب واطبع cost calculated.
على سبيل المثال، إذا كان الإدخالان هما express و4.5، فينبغي أن يكون الناتج:
18.5يوضح هذا قوة نمط Strategy - إذ لا يحتوي OrderProcessor على أي منطق لحساب تكلفة الشحن بنفسه. بل يفوّض المهمة ببساطة إلى الاستراتيجية التي أُسنِدت إليه، مما يجعل من السهل إضافة طرق شحن جديدة (مثل DroneDelivery) دون تعديل المعالج إطلاقًا!
جرّب بنفسك
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", or "overnight")،
// أنشئ استراتيجية الشحن المناسبة وعيّنها على المعالج
// TODO: عالج الطلب واطبع التكلفة المحسوبة
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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تدرّب بنفسك: مترجم C# عبر الإنترنت