00 · OVERVIEWHow to use this guideكيف تستخدم هذا المرجع
Each lecture is broken into concept → diagram → code → "why it matters." Tap the language button at the top right to switch between English and Arabic at any time. Click on any quiz question to test yourself, and on every + to expand details.
Read straight through, or jump to a topic from the table of contents below.
كل محاضرة مقسّمة إلى مفهوم ← مخطط ← كود ← لماذا هذا مهم. اضغط زر اللغة في الأعلى للتبديل بين العربية والإنجليزية في أي وقت. اضغط على أي سؤال اختبار لتجربة نفسك، وعلى علامة + لفتح تفاصيل إضافية.
اقرأ المرجع كاملاً، أو انتقل إلى موضوع محدد من الفهرس التالي.
Table of Contents
الفهرس
- Lecture 01 — Introduction to Software Design & OOPالمحاضرة 1 — مدخل إلى تصميم البرمجيات و OOP
- Lecture 02 — SOLID Principlesالمحاضرة 2 — مبادئ SOLID
- Design Patterns — The Big Pictureأنماط التصميم — الصورة الكبرى
- Lecture 04 — DAL Patterns (DAO, Repository, Factory)المحاضرة 4 — أنماط DAL (DAO، Repository، Factory)
- Lecture 05 — State Design Patternالمحاضرة 5 — نمط الحالة State
- Lecture 06 — Decorator Design Patternالمحاضرة 6 — نمط Decorator
- Past Midterm — Walkthrough & Practiceالامتحان السابق — شرح وتطبيق
- Cheat Sheet — Quick Recallملخص سريع للمراجعة
01 · LECTURE Software Design & OOP Foundations أسس تصميم البرمجيات و OOP
From requirements to a stable, extensible design
من المتطلبات إلى تصميم ثابت قابل للتوسعة
The Software Development Life Cycle
دورة حياة تطوير البرمجيات
Every system begins as a problem and ends as a working solution. The path between them is the SDLC — and your role as a designer lives mostly in the green box below.
كل نظام يبدأ بـمشكلة وينتهي بـحل قابل للتسليم. الطريق بينهما هو دورة حياة تطوير البرمجيات — ودورك كمصمم يكون في الجزء الأخضر أدناه.
The Four Pillars of OOP
الأركان الأربعة لـ OOP
Encapsulation
Hide internal state; expose behavior.
إخفاء الحالة الداخلية وإظهار السلوك فقط.
Abstraction
Define what, not how.
تحديد ماذا يفعل لا كيف.
Inheritance
Reuse and refine a base type.
إعادة استخدام وتخصيص نوع أساسي.
Polymorphism
One call, many implementations.
استدعاء واحد، تنفيذات متعددة.
🛡️ Encapsulation — code exampleالتغليف — مثال كود
Keep fields private, validate inputs, expose intent through methods.
اجعل الحقول private، تحقق من المدخلات، واكشف عن الوظائف عبر الميثودات.
class BankAccount { private double balance; // hidden public void deposit(double amount) { if (amount <= 0) throw new IllegalArgumentException(); balance += amount; } public double getBalance() { return balance; } }
🎭 Abstraction — code exampleالتجريد — مثال كود
Use interfaces or abstract classes as contracts; hide the implementation.
استخدم الواجهات أو الكلاسات المجردة كـعقود، وأخفِ التفاصيل.
interface Shape { double area(); } class Circle implements Shape { private final double r; Circle(double r) { this.r = r; } @Override public double area() { return Math.PI * r * r; } }
🧬 Inheritance — code exampleالوراثة — مثال كود
Use extends to reuse and override behavior. Prefer composition over deep inheritance.
استخدم extends لإعادة استخدام السلوك أو إعادة تعريفه. التكوين (composition) أفضل من سلاسل الوراثة العميقة.
class Animal { public String speak() { return "..."; } } class Dog extends Animal { @Override public String speak() { return "Woof"; } }
🔀 Polymorphism — code exampleتعدد الأشكال — مثال كود
Program to an interface; the runtime picks the correct implementation.
برمج عبر الواجهة؛ والمحرّك يختار التنفيذ الصحيح وقت التشغيل.
List<Shape> shapes = List.of( new Circle(2), new Rectangle(3, 4) ); double total = 0; for (Shape s : shapes) { total += s.area(); // dynamic dispatch }
UML Class Diagram — Quick Reference
مخطط الكلاس UML — مرجع سريع
Case Study Evolution — Virtual Pet Game
دراسة الحالة — لعبة الحيوان الأليف الافتراضي
A pet simulator should support cats, dogs, and monkeys. Watch the design improve in three steps.
محاكي حيوانات أليفة يدعم القطط والكلاب والقرود. شاهد كيف يتطور التصميم في ثلاث خطوات.
① Naïve OOPتصميم ساذج
Three separate classes (Cat, Dog, Monkey) all referenced by User via adopt-cat(), adopt-dog(), etc.
ثلاثة كلاسات منفصلة (Cat, Dog, Monkey) ويُشير إليها User عبر adopt-cat(), adopt-dog()...إلخ.
- Problem 1: User must handle each pet type separately.
- المشكلة 1: يجب أن يتعامل المستخدم مع كل نوع حيوان بشكل مستقل.
- Problem 2: Massive code duplication — name, age, color, energy repeated everywhere.
- المشكلة 2: تكرار هائل في الكود — name و age و color و energy مكررة في كل مكان.
- Problem 3: Adding a new pet type forces modifying
User. - المشكلة 3: إضافة نوع جديد يستوجب تعديل كلاس
User.
② Generalization (Abstract Pet)التعميم (Pet مجرد)
Introduce an abstract Pet with shared fields. Cat, Dog, Monkey all extend it. User now holds a single List<Pet>.
أدخل كلاس مجرد Pet يحتوي على الحقول المشتركة. الكلاسات الفرعية ترث منه، ويحتفظ User بقائمة واحدة List<Pet>.
③ Interfaces (IMovable, IFeedable)الواجهات (IMovable, IFeedable)
Extract behaviors as interfaces. Movement strategies (WalkingOnFour, Jumping) implement IMovable. Feeding strategies (EatBanana, EatDryFood) implement IFeedable.
انقل السلوكيات إلى واجهات. استراتيجيات الحركة (WalkingOnFour, Jumping) تنفّذ IMovable. واستراتيجيات الأكل (EatBanana, EatDryFood) تنفّذ IFeedable.
Exam tip
نصيحة امتحانية
When a question asks "what's wrong with this design?" look for these three signals: (1) code duplication, (2) switch/if-else on type, and (3) changing one class forces editing another. Each signal points to a different SOLID violation.
عندما يسألك السؤال "ما الخطأ في هذا التصميم؟" ابحث عن ثلاث إشارات: (1) تكرار الكود، (2) switch/if-else حسب النوع، (3) تعديل كلاس واحد يجبرك على تعديل آخر. كل إشارة تشير إلى خرق مختلف لمبادئ SOLID.
02 · LECTURE SOLID Principles مبادئ SOLID
Five rules that keep code maintainable as projects grow
خمس قواعد تحافظ على قابلية الصيانة مع نمو المشروع
① Single Responsibility (SRP)المسؤولية الواحدة (SRP)
✗Violationخرق
AreaCalculator both computes the sum AND prints the result. Two reasons to change.
AreaCalculator يحسب المجموع ويطبع الناتج معًا. سببان للتغيير.
class AreaCalculator { shapes: list[]; sum(shapes): double; print-result(result); // 👎 mixed concern }
✓Fixالحل
Split into AreaCalculator (compute) and SumCalculatorPrinter (display). Each class has one job.
قسّم إلى AreaCalculator (الحساب) وSumCalculatorPrinter (الطباعة). كل كلاس يقوم بمهمة واحدة.
class AreaCalculator { sum(...) } class SumCalculatorPrinter { print-to-console(sum) print-to-file(sum) }
② Open / Closed (OCP)المفتوح / المغلق (OCP)
✗Violationخرق
Adding a new shape forces editing sum() with another else if.
إضافة شكل جديد تفرض تعديل sum() بإضافة else if آخر.
foreach (var shape in Shapes) { if (shape is Square sq) areas.Add(Math.Pow(sq.Length, 2)); else if (shape is Circle c) areas.Add(Math.PI * c.Radius * c.Radius); // every new shape = NEW BRANCH 👎 }
✓Fixالحل
Move area() into each shape behind an IShape interface. Adding shapes never touches the calculator.
انقل area() داخل كل شكل خلف واجهة IShape. إضافة الأشكال لا تلمس الـ calculator.
interface IShape { double Area(); } foreach (var s in shapes) areas.Add(s.Area()); // closed for change ✅
③ Liskov Substitution (LSP)استبدال ليسكوف (LSP)
✗Violationخرق
If Shape declares volume(), then Square (a 2D shape) must implement it — but it has no volume! Substituting Square wherever Shape is used breaks expectations.
إذا تضمن Shape ميثود volume()، فالـ Square (ثنائي الأبعاد) ملزم بتنفيذه — رغم أنه لا يملك حجمًا! الاستبدال يكسر التوقعات.
✓Fixالحل
Split into two interfaces: IShape (area) and I3DShape (volume). Square implements only what makes sense.
قسّم إلى واجهتين: IShape (للمساحة) وI3DShape (للحجم). وSquare ينفّذ ما يخصه فقط.
④ Interface Segregation (ISP)فصل الواجهات (ISP)
In the shapes example: forcing Square to implement volume() = ISP violation. Solution: separate IShape and I3DShape.
في مثال الأشكال: إجبار Square على تنفيذ volume() = خرق ISP. الحل: افصل IShape و I3DShape.
⑤ Dependency Inversion (DIP)عكس التبعيات (DIP)
✗Violationخرق
SumCalculatorSaver directly depends on a concrete SqlConnector. Switch DBs → rewrite saver.
SumCalculatorSaver يعتمد مباشرة على SqlConnector ملموس. غيّر قاعدة البيانات → أعد كتابته.
✓Fixالحل
Introduce IDBConnector interface. Concrete SqlConnector and NoSqlConnector implement it. SumCalculatorSaver depends only on the interface.
أنشئ واجهة IDBConnector. الكلاسات SqlConnector و NoSqlConnector تنفّذها. وSumCalculatorSaver يعتمد على الواجهة فقط.
SOLID — fast diagnosis cheatsheet
SOLID — تشخيص سريع
| Symptom in code | Principle violated | العَرَض في الكود | المبدأ المخروق |
|---|---|---|---|
| Class does > 1 unrelated job | SRP | الكلاس يقوم بأكثر من مهمة غير مترابطة | SRP |
| if/switch on type; new feature edits old code | OCP | if/switch حسب النوع؛ كل ميزة جديدة تعدّل كود قائم | OCP |
| Subclass throws "not supported" or returns nonsense | LSP | كلاس فرعي يرمي "not supported" أو يعيد قيمة غير منطقية | LSP |
| Implementor forced to write empty methods | ISP | المنفّذ مجبر على كتابة ميثودات فارغة | ISP |
new ConcreteX() hardcoded inside high-level code | DIP | new ConcreteX() مكتوبة داخل كود عالي المستوى | DIP |
03 · OVERVIEW Design Patterns — The Three Families أنماط التصميم — العائلات الثلاث
Reusable solutions to recurring problems
حلول قابلة لإعادة الاستخدام لمشاكل متكررة
⭐ marks the patterns covered in this course. Note: in Lecture 04 the slides label DAO and Repository as structural, while Factory is creational.
⭐ تشير إلى الأنماط المدروسة في هذه المادة. ملاحظة: في المحاضرة 4 صنّفت الشرائح DAO وRepository كـstructural، بينما Factory creational.
04 · LECTURE Data Access Layer Patterns أنماط طبقة الوصول إلى البيانات
DAO · Repository · Factory Method
DAO · Repository · Factory Method
Where the DAL fits
موقع طبقة DAL
Problem — Student Courses
المشكلة — مقررات الطالب
A console app where staff enters a student ID and the app fetches the student's enrolled courses for the current semester from a relational database.
برنامج كونسول: الموظف يدخل رقم الطالب فيُعيد البرنامج المقررات المسجّلة في الفصل الحالي من قاعدة بيانات علائقية.
DAO — Data Access Object
نمط DAO
- Handles direct DB interaction — opens connections, runs SQL.
- يتعامل مباشرة مع قاعدة البيانات — يفتح الاتصال وينفّذ SQL.
- Performs low-level operations (CRUD on a single table).
- يقوم بعمليات منخفضة المستوى (CRUD على جدول واحد).
- Maps DB rows ↔ domain entities.
- يحوّل صفوف القاعدة إلى كائنات الـ domain والعكس.
- One DAO per table —
StudentDAO,CourseDAO,EnrollmentDAO. - كلّ جدول له DAO خاص —
StudentDAO,CourseDAO,EnrollmentDAO.
Repository
نمط Repository
- Higher-level abstraction over DAOs.
- تجريد أعلى مستوى فوق الـ DAOs.
- Implements business-specific data access (e.g.
getStudentCourses(int)). - ينفّذ عمليات بيانات خاصة بمنطق العمل (مثلاً
getStudentCourses(int)). - Coordinates multiple DAOs for complex queries.
- ينسّق بين عدة DAOs للاستعلامات المعقدة.
Factory Method (Creational)
نمط Factory Method (إنشائي)
Replace direct new SqlConnector() calls with factory.create(). The factory hides creation details and returns objects via a common interface (the "product").
استبدل الاستدعاء المباشر new SqlConnector() بـ factory.create(). الـ factory يُخفي تفاصيل الإنشاء ويعيد الكائنات عبر واجهة موحّدة (المنتج).
Why Factory Method?
لماذا Factory Method؟
Use it when the way of creating objects might change (different DBs, different parsers, different attack styles in a game). The client treats all products as the abstract type — they don't know or care about the concrete class. Best paired with the Strategy pattern.
استخدمه عندما قد تتغير طريقة إنشاء الكائنات (قواعد بيانات مختلفة، محلّلات مختلفة، أساليب هجوم في لعبة). العميل يتعامل مع جميع المنتجات عبر النوع المجرد — دون أن يعرف الكلاس الملموس. يُستخدم عادةً مع نمط Strategy.
05 · LECTURE State Design Pattern نمط الحالة State
Behavioral · "An object that changes its class"
سلوكي · "كائن يتغيّر سلوكه كأنه غيّر صنفه"
Coffee Machine Example
مثال: ماكينة القهوة
A smart coffee machine has 3 actions: insertMoney(), selectCoffee(), serveCoffee() — but their meaning depends on the current state.
ماكينة قهوة ذكية بثلاث عمليات: insertMoney() و selectCoffee() و serveCoffee() — لكن المعنى يختلف بحسب الحالة الحالية.
The Pattern Structure
بنية النمط
Implementation Walk-through
شرح التنفيذ
1️⃣ The State interfaceواجهة State
public interface State { void insertCoin(); void selectCoffee(); void ServeCoffee(); }
2️⃣ A concrete state — IdleStateحالة ملموسة — IdleState
Each concrete state holds a reference to the Machine so it can request a transition.
كل حالة ملموسة تحتفظ بمرجع للـ Machine لتطلب الانتقال إلى حالة جديدة.
public class IdleState : State { private Machine machine; public IdleState(Machine machine) { this.machine = machine; } public void insertCoin() { Console.WriteLine("Coin inserted"); machine.ChangeState(new SelectingState(machine)); } public void selectCoffee() { Console.WriteLine("Please insert coin first"); } public void ServeCoffee() { Console.WriteLine("Insert coin and select first"); } }
3️⃣ The Context — Machineالسياق — Machine
The Machine delegates every action to its current state and exposes ChangeState().
يفوّض الـ Machine كل عملية إلى الحالة الحالية، ويوفّر ChangeState() للتبديل.
public class Machine { private State currentState; public Machine() { currentState = new IdleState(this); } public void ChangeState(State newState) { currentState = newState; } public void insertCoin() { currentState.insertCoin(); } public void selectCoffee() { currentState.selectCoffee(); } public void ServeCoffee() { currentState.ServeCoffee(); } }
4️⃣ Clientالكلاس الرئيسي (Client)
var machine = new Machine(); machine.insertCoin(); // idle → selecting machine.selectCoffee(); // selecting → serve machine.ServeCoffee(); // serve → idle
06 · LECTURE Decorator Design Pattern نمط Decorator
Structural · "Wrapping" objects to add behavior
هيكلي · "تغليف" الكائنات لإضافة سلوك
The Notifier Problem (revisited)
مشكلة الإشعارات (نعود إليها)
A notification system needs to support Email, SMS, Facebook, Slack — and combinations of them.
نظام الإشعارات يجب أن يدعم البريد، SMS، فيسبوك، Slack — ومجموعات منها.
✗Inheritance Explodesانفجار الوراثة
Every new combination = new subclass. SMS+Slack, Email+Facebook+Slack, Facebook+Slack… Inheritance is static — chosen at compile time, can't combine multiple parents.
كل تركيبة جديدة = كلاس جديد. SMS+Slack، Email+Facebook+Slack، Facebook+Slack… الوراثة ثابتة — تُختار وقت التحضير، ولا يمكن دمج عدة آباء.
✓Composition Winsالتكوين يفوز
A wrapper holds a reference to the wrapped object, has the same interface, and can act before/after delegating. Stack wrappers freely.
المغلِّف يحمل مرجعًا للمغلَّف، له نفس الواجهة، ويستطيع التدخل قبل/بعد التفويض. تستطيع تكديس المغلفات بحرية.
Pattern Structure
بنية النمط
Implementation
التنفيذ
① Common interfaceالواجهة المشتركة
public interface Notifier { void send(String message); }
② Concrete component (base behavior)المكوّن الملموس (السلوك الأساسي)
public class EmailNotifier implements Notifier { @Override public void send(String message) { System.out.println("Sending Email: " + message); } }
③ Base decorator (the wrapper)المُغلِّف الأساسي
Holds a reference to a Notifier, implements Notifier itself, and forwards every call.
يحتفظ بمرجع لـ Notifier، وينفّذ Notifier، ويمرّر كل استدعاء.
public class NotifierDecorator implements Notifier { protected Notifier wrappee; public NotifierDecorator(Notifier wrappee) { this.wrappee = wrappee; } @Override public void send(String message) { wrappee.send(message); // delegate first } }
④ Concrete decorators add their own behaviorالمُغلِّفات الملموسة تضيف سلوكها
public class SMSNotifier extends NotifierDecorator { public SMSNotifier(Notifier wrappee) { super(wrappee); } @Override public void send(String message) { super.send(message); // chain to inner System.out.println("Sending SMS: " + message); } } public class FacebookNotifier extends NotifierDecorator { public FacebookNotifier(Notifier wrappee) { super(wrappee); } @Override public void send(String message) { super.send(message); System.out.println("Sending Facebook: " + message); } }
⑤ Client stacks decoratorsالعميل يكدّس المُغلِّفات
Notifier notifier = new EmailNotifier(); notifier = new SMSNotifier(notifier); notifier = new FacebookNotifier(notifier); notifier = new SlackNotifier(notifier); notifier.send("Hello design students!"); // Output: // Sending Email: ... // Sending SMS: ... // Sending Facebook: ... // Sending Slack: ...
super keyword reminder
تذكير بكلمة super
super.send() calls the parent's version. In a decorator, that's how the call chains down the wrap stack until it hits the original EmailNotifier.
super.send() يستدعي نسخة الأب. في الـ decorator، هذه هي الطريقة التي ينزل بها الاستدعاء عبر سلسلة المغلّفات حتى يصل إلى EmailNotifier الأصلي.
Practice — Coffee Ordering System
تطبيق — نظام طلب القهوة
Coffee ($3) → Milk (+$1) → Sugar (+$2) → Whipped Cream (+$1). Each addition increases description and price.
قهوة ($3) → حليب ($1+) → سكر ($2+) → كريمة ($1+). كل إضافة تزيد الوصف والسعر.
Try it yourself. Component = Beverage with cost() and desc(). Concrete = Coffee. Base decorator = BeverageDecorator. Concrete decorators = Milk, Sugar, WhippedCream.
جرّب بنفسك. Component = Beverage فيها cost() و desc(). Concrete = Coffee. Base decorator = BeverageDecorator. Concrete decorators = Milk، Sugar، WhippedCream.
🔍 Sample solutionحل نموذجي
interface Beverage { double cost(); String desc(); } class Coffee implements Beverage { public double cost() { return 3.0; } public String desc() { return "Coffee"; } } abstract class BeverageDecorator implements Beverage { protected Beverage wrappee; BeverageDecorator(Beverage b) { wrappee = b; } } class Milk extends BeverageDecorator { Milk(Beverage b) { super(b); } public double cost() { return wrappee.cost() + 1; } public String desc() { return wrappee.desc() + ", Milk"; } } // Sugar and WhippedCream follow the same pattern. // Client: Beverage b = new Coffee(); b = new Milk(b); b = new Sugar(b); b = new WhippedCream(b); System.out.println(b.desc() + " — $" + b.cost()); // Coffee, Milk, Sugar, WhippedCream — $7.0
07 · PAST MIDTERM Walkthrough & Practice شرح وتطبيق
SPU 2023–2024 · Q1 + Q2 + Q3 with model answers
SPU 2023–2024 · س1 + س2 + س3 مع نموذج الإجابات
Question 01 — Multiple Choice
السؤال الأول — اختيار من متعدد
Which creational pattern ensures a class has only one instance and provides a global access point?
أي نمط إنشائي يضمن أن للكلاس نسخة وحيدة ويوفّر نقطة وصول عامة لها؟
Singleton is the canonical "exactly one instance + global access" pattern. Factory Method creates objects but doesn't restrict count. Proxy is structural (controls access). Decorator adds behavior.
Singleton هو النمط الكلاسيكي لـ "نسخة وحيدة + وصول عام". Factory Method يُنشئ كائنات لكن لا يقيد العدد. Proxy نمط هيكلي للتحكم بالوصول. Decorator يضيف سلوكًا.
Which OOP pillar is primarily applied in the Strategy pattern?
أي ركن من أركان OOP يُطبَّق أساساً في نمط Strategy؟
Strategy = client calls strategy.execute() through a common interface; the runtime picks the correct concrete strategy. That's polymorphism. (Abstraction defines the contract; polymorphism is what makes the call work.)
Strategy = العميل يستدعي strategy.execute() عبر واجهة مشتركة، والمحرك يختار الاستراتيجية الصحيحة وقت التشغيل. هذا polymorphism. (التجريد يُعرّف العقد، أما polymorphism فهو ما يُشغّل الاستدعاء.)
The Template Method pattern is based on:
نمط Template Method يعتمد على:
Template Method defines the skeleton of an algorithm in a base class and lets subclasses override specific steps. The mechanism is inheritance + method overriding. Strategy uses aggregation; Template Method uses inheritance — that's the classic exam contrast.
Template Method يضع هيكل الخوارزمية في الكلاس الأب ويترك للأبناء تنفيذ خطوات معينة. الآلية هي الوراثة + override. Strategy يستخدم aggregation، أما Template Method فيستخدم الوراثة — هذا الفرق الكلاسيكي في الامتحانات.
Question 02 — UserRepository Refactor (7 marks)
السؤال الثاني — إعادة هيكلة UserRepository (7 علامات)
public class SqlConnection { public void Connect() { Console.WriteLine("Connected to SQL Server"); } public void Execute(string query) { Console.WriteLine($"Executing SQL: {query}"); } } public class UserRepository { private readonly SqlConnection _connection; public UserRepository() { _connection = new SqlConnection(); // 👎 hardcoded } public void SaveUser(string username) { _connection.Connect(); _connection.Execute($"INSERT INTO Users VALUES ('{username}')"); } }
① Which SOLID principle is violated? (1 mark)أي مبدأ SOLID مخروق؟ (علامة 1)
UserRepository (high-level) directly depends on the concrete SqlConnection (low-level). Both should depend on an abstraction. Switching to MongoDB or any other store would force editing the repository — also violating OCP.
UserRepository (عالي المستوى) يعتمد مباشرة على SqlConnection ملموس (منخفض المستوى). يجب أن يعتمد كلاهما على تجريد. التبديل إلى MongoDB أو أي مخزن آخر يفرض تعديل الـ repository — وهذا أيضاً خرق لـ OCP.
② Refactor — class diagram (3 marks)إعادة الهيكلة — مخطط الكلاس (3 علامات)
Introduce IDbConnection interface. UserRepository takes it in the constructor (Dependency Injection).
أنشئ واجهة IDbConnection. الـ UserRepository يستقبلها في الـ constructor (حقن التبعية).
public interface IDbConnection { void Connect(); void Execute(string query); } public class SqlConnection : IDbConnection { public void Connect() { /* ... */ } public void Execute(string q) { /* ... */ } } public class UserRepository { private readonly IDbConnection _connection; public UserRepository(IDbConnection connection) { _connection = connection; // injected } public void SaveUser(string username) { _connection.Connect(); _connection.Execute($"INSERT INTO Users VALUES ('{username}')"); } }
③ Add a MongoDB connection (1 mark)أضف اتصال MongoDB (علامة 1)
Just add a new class — no other code changes (this is the OCP win).
أضف كلاسًا جديدًا فقط — دون تعديل أي كود آخر (هذا انتصار OCP).
public class MongoConnection : IDbConnection { public void Connect() { Console.WriteLine("Connected to MongoDB"); } public void Execute(string query) { Console.WriteLine($"Mongo executing: {query}"); } } // Usage: var repo = new UserRepository(new MongoConnection()); repo.SaveUser("raghad");
④ Purpose & benefit of Repository (2 marks)الغرض من Repository وفوائده (علامتان)
Purpose: the Repository pattern provides a higher-level abstraction over data access. Business logic asks the repository for "users," "orders," etc. — without knowing whether the data sits in SQL, MongoDB, an API, or memory.
الغرض: يوفّر Repository تجريداً أعلى مستوى فوق طبقة الوصول إلى البيانات. منطق العمل يطلب "users" أو "orders"... دون أن يعرف إن كانت البيانات في SQL أو MongoDB أو API أو الذاكرة.
- Separation of concerns — business logic stays clean.
- فصل الاهتمامات — منطق العمل يبقى نظيفًا.
- Testability — swap real DB for an in-memory fake during tests.
- قابلية الاختبار — استبدل القاعدة الحقيقية بنسخة في الذاكرة أثناء الاختبار.
- Centralized queries — business-specific data methods live in one place.
- تمركز الاستعلامات — كل استعلامات العمل في مكان واحد.
- Easy to change storage — swap DAOs/connections without touching consumers.
- سهولة تغيير التخزين — بدّل الـ DAOs أو الاتصالات دون لمس مستهلكي البيانات.
Question 03 — Hero Attack with Factory (5 marks)
السؤال الثالث — هجمات البطل مع Factory (5 علامات)
The original design uses Strategy: a Hero aggregates an IAttackStrategy with concrete classes MeleeAttack, RangedAttack, MagicalAttack. Redesign so that strategies are created via a factory.
التصميم الأصلي يستخدم Strategy: Hero يحتوي IAttackStrategy مع كلاسات ملموسة MeleeAttack و RangedAttack و MagicalAttack. أعد التصميم بحيث تُنشأ الاستراتيجيات عبر factory.
Idea: introduce AttackFactory with a method create(type) that returns an IAttackStrategy. The Hero asks the factory for a strategy by name/enum — never calls new directly.
الفكرة: أنشئ AttackFactory فيها ميثود create(type) ترجع IAttackStrategy. الـ Hero يطلب الاستراتيجية من الـ factory باسم/enum — ولا يستدعي new مباشرة.
interface IAttackStrategy { void attack(); } class MeleeAttack implements IAttackStrategy { public void attack(){ /*...*/ } } class RangedAttack implements IAttackStrategy { public void attack(){ /*...*/ } } class MagicalAttack implements IAttackStrategy { public void attack(){ /*...*/ } } enum AttackType { MELEE, RANGED, MAGICAL } class AttackFactory { public IAttackStrategy create(AttackType type) { switch (type) { case MELEE: return new MeleeAttack(); case RANGED: return new RangedAttack(); case MAGICAL: return new MagicalAttack(); default: throw new IllegalArgumentException(); } } } class Hero { private IAttackStrategy attackStyle; public void setAttack(AttackType type, AttackFactory f) { this.attackStyle = f.create(type); } public void attack() { attackStyle.attack(); } }
Why this matters: the Hero never calls new MeleeAttack(). Adding new attack types only changes the factory — Hero stays untouched. Factory + Strategy = a classic combo.
لماذا هذا مهم: الـ Hero لا يستدعي new MeleeAttack() أبدًا. إضافة هجمات جديدة تتطلب تعديل factory فقط — والـ Hero يبقى كما هو. Factory + Strategy = تركيبة كلاسيكية.
08 · CHEAT SHEET Quick Recall — One-Page Summary ملخص سريع — صفحة واحدة
Print this. Memorize it. Walk into the exam.
اطبع هذا. احفظه. ادخل الامتحان.
SOLID — One-line Each
SOLID — سطر واحد لكل مبدأ
| · | Principle | One-liner | المبدأ | باختصار |
|---|---|---|---|---|
| S | Single Responsibility | One reason to change. | المسؤولية الواحدة | سبب واحد للتغيير. |
| O | Open / Closed | Open to extend, closed to modify. | مفتوح / مغلق | مفتوح للتوسعة، مغلق على التعديل. |
| L | Liskov Substitution | Subtype must keep parent's promise. | استبدال ليسكوف | الكلاس الفرعي يحفظ وعد الأب. |
| I | Interface Segregation | Many small interfaces beat one fat interface. | فصل الواجهات | واجهات صغيرة أفضل من واحدة ضخمة. |
| D | Dependency Inversion | Depend on abstractions, not concretions. | عكس التبعيات | اعتمد على التجريد لا على الملموس. |
Patterns — When to Use Each
الأنماط — متى تستخدم كل واحد
| Pattern | Family | Use when… | النمط | استخدمه عندما… |
|---|---|---|---|---|
| Singleton | Creational | …you need exactly one shared instance (logger, config). | Singleton | …تحتاج نسخة وحيدة مشتركة (logger، config). |
| Factory Method | Creational | …you want to create objects without binding to concrete classes. | Factory Method | …تريد إنشاء كائنات دون ربط بالكلاسات الملموسة. |
| Strategy | Behavioral | …multiple algorithms can be swapped at runtime by the client. | Strategy | …خوارزميات متعددة يمكن تبديلها وقت التشغيل من العميل. |
| State | Behavioral | …an object's behavior depends heavily on its current state and changes between states. | State | …سلوك الكائن يعتمد بشدة على حالته الحالية ويتغيّر بين الحالات. |
| Template Method | Behavioral | …you want a fixed algorithm skeleton with overridable steps (uses inheritance). | Template Method | …تريد هيكل خوارزمية ثابت مع خطوات قابلة للتعديل (يستخدم الوراثة). |
| Decorator | Structural | …you want to add behavior to individual objects dynamically by wrapping them. | Decorator | …تريد إضافة سلوك ديناميكي لكائنات بعينها عن طريق تغليفها. |
| DAO | Structural | …you need to encapsulate raw DB access for a single table/entity. | DAO | …تحتاج تغليف الوصول الخام لقاعدة البيانات لجدول واحد. |
| Repository | Structural | …you want a higher-level data API that the business logic can depend on. | Repository | …تريد واجهة بيانات أعلى مستوى يستطيع منطق العمل الاعتماد عليها. |
Strategy vs. State vs. Decorator vs. Template Method
المقارنة بين Strategy / State / Decorator / Template Method
| Pattern | Mechanism | Who picks the variation? | النمط | الآلية | من يختار التنوّع؟ |
|---|---|---|---|---|---|
| Strategy | Composition | Client (explicitly) | Strategy | Composition | العميل (صراحةً) |
| State | Composition | The state objects themselves | State | Composition | الحالات نفسها |
| Decorator | Composition (wrapping) | Client builds the wrap stack | Decorator | Composition (تغليف) | العميل يبني سلسلة التغليف |
| Template Method | Inheritance | Subclass (at compile time) | Template Method | الوراثة | الكلاس الفرعي (وقت التحضير) |
Final exam day tips
نصائح يوم الامتحان
- Read the code first. Look for
new ConcreteX(),if/switch on type, and methods that print + compute. - اقرأ الكود أولاً. ابحث عن
new ConcreteX()، وif/switchحسب النوع، وميثودات تطبع وتحسب معاً. - Name the violation, then the fix. "Violates DIP because… solved by injecting an interface…"
- سمِّ الخرق ثم الحل. "خرق DIP لأن… الحل بحقن واجهة…"
- Draw the diagram before coding. Boxes for classes, dashed arrows for implements, hollow triangle for extends.
- ارسم المخطط قبل الكود. صناديق للكلاسات، أسهم متقطعة لـ implements، مثلث مجوف لـ extends.
- For Decorator code: always remember
super.method()chains the call to the inner wrappee. - في كود Decorator: لا تنسَ أن
super.method()يمرر الاستدعاء إلى الكائن المُغلَّف الداخلي. - For State code: the context (Machine, Coffee Machine) holds the state and forwards every call.
- في كود State: السياق (Machine، CoffeeMachine) يحمل الحالة ويمرّر إليها كل استدعاء.