في عالم تطوير البرمجيات، كتابة كود نظيف وقابل للصيانة أمر مهم جداً عشان تضمن إن التطبيقات بتاعتك تفضل فعالة وسهلة في التعديل على المدى الطويل. لكن من أكبر المشاكل اللي بتواجه المطورين هي الاستخدام المفرط لجمل 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);
هنا بنستخدم 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();
هنا، كل أمر بنمثله ككائن باستخدام 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();
باستخدام 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");
باستخدام 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();
في المثال ده، Factory Pattern بيساعدك تنشئ الكائنات بدون الحاجة لاستخدام if else
.
الخلاصة
الأنماط دي زي Strategy, Command, State, Chain of Responsibility, و Factory هتخليك تكتب كود نظيف ومرن بعيد عن تعقيدات جمل if else
. الأنماط دي مش بس بتسهل التوسعة في المستقبل، لكن كمان بتخلي الكود أكثر قابلية للصيانة. جرب الأنماط دي في مشاريعك الجاية عشان تحسن الكود وتجعل العمل أكثر فاعلية.
Top comments (0)