DEV Community

ahmedmohamedhussein
ahmedmohamedhussein

Posted on

1

Ditch the 'If Else': Mastering Design Patterns for Cleaner, Scalable Code in C# (Arabic language)

في عالم تطوير البرمجيات، كتابة كود نظيف وقابل للصيانة أمر مهم جداً عشان تضمن إن التطبيقات بتاعتك تفضل فعالة وسهلة في التعديل على المدى الطويل. لكن من أكبر المشاكل اللي بتواجه المطورين هي الاستخدام المفرط لجمل if else. في البداية، الجمل دي ممكن تكون سريعة وسهلة، لكن مع الوقت، الكود بيتعقد بشكل رهيب وبيصعب فهمه وصيانته. في المقال ده هنستعرض مع بعض شوية أنماط تصميم (Design Patterns) هتساعدك تتجنب التعقيد اللي بيجي من جمل if else، وتخلي الكود بتاعك أنظف وأسهل في التطوير.

هنشرح خمس أنماط تصميم أساسية تقدر تستخدمها لتحسين كودك وتجنب "if else". كل نمط هنشرح فكرته بأمثلة واقعية بالكود باستخدام لغة C#.


1. Strategy Pattern: Choosing the Right Behavior at Runtime

الفكرة:
نمط الاستراتيجية بيسمح لك تحدد مجموعة من السلوكيات (أو الاستراتيجيات)، وتخزن كل واحدة منهم في كلاس منفصل، وبعد كده تختار الاستراتيجية المناسبة في وقت التشغيل. بدل ما تكتب if else طويل لاختيار السلوك الصحيح، تقدر تختار الاستراتيجية بسهولة.

مثال واقعي:
افترض عندك تطبيق دفع إلكتروني بيعرض عدة طرق دفع زي بطاقة ائتمان أو بايبال أو الدفع عند الاستلام. بدل ما تكتب if else لكل طريقة دفع، تقدر تستخدم Strategy Pattern لاختيار طريقة الدفع المناسبة في وقت التشغيل.

الكود:

public interface IPaymentStrategy
{
    void Pay(double amount);
}

public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(double amount)
    {
        Console.WriteLine($"Paid {amount} using Credit Card");
    }
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(double amount)
    {
        Console.WriteLine($"Paid {amount} using PayPal");
    }
}

public class PaymentContext
{
    private readonly IPaymentStrategy _paymentStrategy;

    public PaymentContext(IPaymentStrategy paymentStrategy)
    {
        _paymentStrategy = paymentStrategy;
    }

    public void ExecutePayment(double amount)
    {
        _paymentStrategy.Pay(amount);
    }
}

// الاستخدام
var paymentMethod = new PayPalPayment(); // دي ممكن تتغير حسب اختيار المستخدم
var paymentContext = new PaymentContext(paymentMethod);
paymentContext.ExecutePayment(100);
Enter fullscreen mode Exit fullscreen mode

هنا بنستخدم Strategy Pattern عشان نحدد طريقة الدفع بدون الحاجة لجمل if else كثيرة.


2. Command Pattern: Encapsulating Requests as Objects

الفكرة:
نمط الأمر (Command Pattern) بيسمح لك بتغليف الطلبات (زي الأوامر أو العمليات) في كائنات. ده بيساعدك تفصل بين الشخص اللي بيطلب التنفيذ وبين الكود اللي بينفذ العمل، وبيخلي الكود أكثر مرونة وسهولة في التوسع.

مثال واقعي:
افترض إنك عندك نظام تحكم عن بُعد في البيت. ممكن يكون عندك أوامر زي "تشغيل الإضاءة"، "إيقاف المروحة"، وهكذا. بدل ما تكتب if else لكل أمر، تقدر تستخدم Command Pattern لتمثيل كل أمر ككائن منفصل.

الكود:

public interface ICommand
{
    void Execute();
}

public class TurnOnLightsCommand : ICommand
{
    public void Execute()
    {
        Console.WriteLine("Turning on the lights");
    }
}

public class TurnOffFanCommand : ICommand
{
    public void Execute()
    {
        Console.WriteLine("Turning off the fan");
    }
}

public class RemoteControl
{
    private ICommand _command;

    public void SetCommand(ICommand command)
    {
        _command = command;
    }

    public void PressButton()
    {
        _command.Execute();
    }
}

// الاستخدام
var remote = new RemoteControl();
var lightsOn = new TurnOnLightsCommand();
remote.SetCommand(lightsOn);
remote.PressButton();

var fanOff = new TurnOffFanCommand();
remote.SetCommand(fanOff);
remote.PressButton();
Enter fullscreen mode Exit fullscreen mode

هنا، كل أمر بنمثله ككائن باستخدام Command Pattern، وده بيخلينا نتجنب تعقيد الكود بجمل if else.


3. State Pattern: Changing Behavior Based on State

الفكرة:
نمط الحالة (State Pattern) بيسمح للكائن إنه يغير سلوكه بناءً على حالته الداخلية. ده مفيد جدًا لو الكائن بيعمل حاجات مختلفة في حالات مختلفة، وبدل ما تكتب if else عشان تحدد الحالة، تقدر تستخدم النمط ده بشكل أسهل.

مثال واقعي:
افترض إن عندك مشغل فيديو بيكون في حالات مختلفة زي تشغيل، إيقاف مؤقت، وإيقاف. كل حالة ليها سلوك مختلف. بدل ما تكتب if else، تقدر تستخدم State Pattern لتغيير السلوك بناءً على الحالة.

الكود:

public interface IVideoPlayerState
{
    void Play();
    void Pause();
}

public class PlayingState : IVideoPlayerState
{
    public void Play()
    {
        Console.WriteLine("Video is already playing");
    }

    public void Pause()
    {
        Console.WriteLine("Pausing the video");
    }
}

public class PausedState : IVideoPlayerState
{
    public void Play()
    {
        Console.WriteLine("Resuming the video");
    }

    public void Pause()
    {
        Console.WriteLine("Video is already paused");
    }
}

public class VideoPlayer
{
    private IVideoPlayerState _state;

    public VideoPlayer()
    {
        _state = new PlayingState(); // الحالة الأولية
    }

    public void SetState(IVideoPlayerState state)
    {
        _state = state;
    }

    public void PressPlay()
    {
        _state.Play();
    }

    public void PressPause()
    {
        _state.Pause();
    }
}

// الاستخدام
var player = new VideoPlayer();
player.PressPause();

player.SetState(new PausedState());
player.PressPlay();
Enter fullscreen mode Exit fullscreen mode

باستخدام State Pattern بنغير سلوك الفيديو بدون ما نستخدم if else.


4. Chain of Responsibility Pattern: Passing Requests Along a Chain of Handlers

الفكرة:
نمط سلسلة المسؤولية بيسمح لك بتمرير الطلبات عبر سلسلة من المعالجات. كل معالج بيقرر إذا كان هيحل المشكلة أو هيمررها للمعالج التالي. ده بيخلي الكود أكثر مرونة وبيساعد في تجنب if else طويل.

مثال واقعي:
افترض إنك عندك نظام دعم فني، وفيه مستويات مختلفة للدعم زي دعم المستوى 1، المستوى 2، و المستوى 3. كل مستوى ممكن يحل المشكلة أو يمررها للمستوى التالي.

الكود:

public abstract class SupportHandler
{
    protected SupportHandler _nextHandler;

    public void SetNextHandler(SupportHandler nextHandler)
    {
        _nextHandler = nextHandler;
    }

    public abstract void HandleRequest(string issue);
}

public class Level1Support : SupportHandler
{
    public override void HandleRequest(string issue)
    {
        if (issue == "simple issue")
        {
            Console.WriteLine("Level 1 solved the issue");
        }
        else
        {
            Console.WriteLine("Passing to Level 2");
            _nextHandler?.HandleRequest(issue);
        }
    }
}

public class Level2Support : SupportHandler
{
    public override void HandleRequest(string issue)
    {
        if (issue == "moderate issue")
        {
            Console.WriteLine("Level 2 solved the issue");
        }
        else
        {
            Console.WriteLine("Passing to Level 3");
            _nextHandler?.HandleRequest(issue);
        }
    }
}

public class Level3Support : SupportHandler
{
    public override void HandleRequest(string issue)
    {
        Console.WriteLine($"Level 3 solved the issue: {issue}");
    }
}

// الاستخدام
var level1 = new Level1Support();
var level2 = new Level2Support();
var level3 = new Level3Support();

level1.SetNextHandler(level2);
level2.SetNextHandler(level3);

level1.HandleRequest("simple issue");
level1.HandleRequest("moderate issue");
level1.HandleRequest("complex issue");
Enter fullscreen mode Exit fullscreen mode

باستخدام Chain of Responsibility Pattern، بنمرر الطلبات عبر السلسلة بدون الحاجة لجمل if else.


5. Factory Pattern: Creating Objects Without Knowing Their Exact Class

الفكرة:
نمط المصنع بيسمح لك بإنشاء كائنات بدون ما تعرف بالضبط النوع اللي هتستخدمه. ده بيخلي عملية إنشاء الكائنات أكثر مرونة ويساعدك تتجنب كتابة if else لاختيار الكائن المناسب.

مثال واقعي:
افترض إنك عندك مصنع سيارات بينتج

أنواع مختلفة زي سيارات، دراجات نارية، و شاحنات. بدل ما تكتب if else عشان تختار النوع، تقدر تستخدم Factory Pattern.

الكود:

public abstract class Vehicle
{
    public abstract void Drive();
}

public class Car : Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Driving a car");
    }
}

public class Bike : Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Riding a bike");
    }
}

public class VehicleFactory
{
    public Vehicle CreateVehicle(string vehicleType)
    {
        if (vehicleType == "car")
            return new Car();
        else if (vehicleType == "bike")
            return new Bike();

        throw new ArgumentException("Invalid vehicle type");
    }
}

// الاستخدام
var factory = new VehicleFactory();
var car = factory.CreateVehicle("car");
car.Drive();

var bike = factory.CreateVehicle("bike");
bike.Drive();
Enter fullscreen mode Exit fullscreen mode

في المثال ده، Factory Pattern بيساعدك تنشئ الكائنات بدون الحاجة لاستخدام if else.


الخلاصة

الأنماط دي زي Strategy, Command, State, Chain of Responsibility, و Factory هتخليك تكتب كود نظيف ومرن بعيد عن تعقيدات جمل if else. الأنماط دي مش بس بتسهل التوسعة في المستقبل، لكن كمان بتخلي الكود أكثر قابلية للصيانة. جرب الأنماط دي في مشاريعك الجاية عشان تحسن الكود وتجعل العمل أكثر فاعلية.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more