SSD · Study Reference
Software System Design · Practical

A complete study reference — from OOP to Design Patterns.

مرجع دراسي شامل — من OOP إلى أنماط التصميم.

Bilingual, exam-focused notes covering all six lectures plus walk-throughs of the previous midterm. Tap any topic to begin.

ملخص ثنائي اللغة موجّه للامتحان، يغطي المحاضرات الست بالكامل مع شرح أسئلة الامتحان السابق. اضغط على أي عنوان للبدء.

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.

كل محاضرة مقسّمة إلى مفهوم ← مخطط ← كود ← لماذا هذا مهم. اضغط زر اللغة في الأعلى للتبديل بين العربية والإنجليزية في أي وقت. اضغط على أي سؤال اختبار لتجربة نفسك، وعلى علامة + لفتح تفاصيل إضافية.

اقرأ المرجع كاملاً، أو انتقل إلى موضوع محدد من الفهرس التالي.

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.

كل نظام يبدأ بـمشكلة وينتهي بـحل قابل للتسليم. الطريق بينهما هو دورة حياة تطوير البرمجيات — ودورك كمصمم يكون في الجزء الأخضر أدناه.

Problem Requirements elicitation Analysis DESIGN System Object ← YOU ARE HERE Implement Testing
Architecture vs. Design المعمارية مقابل التصميم Architecture = the skeleton of the building (layers, components, communication). Design = the rooms and furniture inside (classes, methods, relationships). In this course, we focus on the detailed design of each component. المعمارية (Architecture) = الهيكل العام للنظام (طبقات، مكونات، طرق التواصل). التصميم (Design) = الغرف والأثاث الداخلي (الكلاسات، الميثودات، العلاقات). في هذه المادة نركّز على التصميم التفصيلي لكل مكوّن.

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 — مرجع سريع

Generalization (extends) Parent Child Realization (implements) «interface» IShape Circle Aggregation (has-a) Library Book Composition (owns) House Room Association Class A 1..* Class B Dependency (uses) Service «use» Logger Visibility (inside a class): + public - private # protected ~ package Italic class name = abstract · Italic method = abstract method · Underlined = static

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>.

Solvedتم حلّه All three problems are addressed — but eating logic is still duplicated (cat and dog both eat dry food the same way). تم حل المشاكل الثلاث — لكن منطق الأكل لا يزال مكررًا (القط والكلب كلاهما يأكل الطعام الجاف بنفس الطريقة).

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.

Benefitsالفوائد ✔ No duplication · ✔ Easily extendable · ✔ Behaviors swappable at runtime · ✔ Pure abstraction. ✔ لا تكرار · ✔ سهلة التوسعة · ✔ سلوك قابل للتبديل وقت التشغيل · ✔ تجريد كامل.

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

خمس قواعد تحافظ على قابلية الصيانة مع نمو المشروع

SSingle Responsibility
OOpen / Closed
LLiskov Substitution
IInterface Segregation
DDependency Inversion

Single Responsibility (SRP)المسؤولية الواحدة (SRP)

Definitionالتعريف A class should have one and only one reason to change. One job, one class. يجب أن يكون للكلاس سبب واحد فقط للتغيير. مهمة واحدة، كلاس واحد.

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)

Definitionالتعريف Software entities should be open for extension, closed for modification. Add new behavior without touching working code. الكيانات يجب أن تكون مفتوحة للتوسعة، مغلقة على التعديل. أضف سلوكًا جديدًا دون لمس الكود الذي يعمل أصلاً.

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)

Definitionالتعريف A subclass must be usable wherever its parent is expected — without breaking behavior. يجب أن تكون الكلاسات الفرعية قابلة للاستخدام أينما يُتوقع الأب — دون أن تكسر السلوك.

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 ينفّذ ما يخصه فقط.

Visual analogy تشبيه بصري Sam makes coffee. Eden is Sam's child. If asked for coffee, Eden should be able to make coffee (LSP ✓). If Eden hands you water instead — LSP violated. سام يصنع القهوة. إيدن ابن سام. إذا طُلب من إيدن قهوة، يجب أن يقدّم قهوة (LSP ✓). إذا قدّم ماءً بدلاً منها — خرق LSP.

Interface Segregation (ISP)فصل الواجهات (ISP)

Definitionالتعريف Clients should not be forced to depend on methods they do not use. Many small interfaces > one fat one. لا تجبر العميل على الاعتماد على ميثودات لا يستخدمها. عدة واجهات صغيرة أفضل من واجهة ضخمة.

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)

Definitionالتعريف High-level modules should not depend on low-level modules. Both should depend on abstractions. الوحدات عالية المستوى لا يجب أن تعتمد على الوحدات منخفضة المستوى. كلاهما يعتمد على التجريد.

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 codePrinciple violated العَرَض في الكودالمبدأ المخروق
Class does > 1 unrelated jobSRP الكلاس يقوم بأكثر من مهمة غير مترابطةSRP
if/switch on type; new feature edits old codeOCP if/switch حسب النوع؛ كل ميزة جديدة تعدّل كود قائمOCP
Subclass throws "not supported" or returns nonsenseLSP كلاس فرعي يرمي "not supported" أو يعيد قيمة غير منطقيةLSP
Implementor forced to write empty methodsISP المنفّذ مجبر على كتابة ميثودات فارغةISP
new ConcreteX() hardcoded inside high-level codeDIP new ConcreteX() مكتوبة داخل كود عالي المستوىDIP

03 · OVERVIEW Design Patterns — The Three Families أنماط التصميم — العائلات الثلاث

Reusable solutions to recurring problems

حلول قابلة لإعادة الاستخدام لمشاكل متكررة

Design Patterns Creational • Factory Method • Abstract Factory • Singleton • Builder "How objects are created" Structural • Decorator ⭐ • Adapter • DAO • Repository "How objects compose" Behavioral • Strategy • State ⭐ • Template Method • Observer "How objects behave"

⭐ 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

Application User Interface Business Logic DATA ACCESS LAYER ⭐

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.

برنامج كونسول: الموظف يدخل رقم الطالب فيُعيد البرنامج المقررات المسجّلة في الفصل الحالي من قاعدة بيانات علائقية.

Enter ID
إدخال الرقم
Connect DB
الاتصال بالقاعدة
Fetch Courses
جلب المقررات
Print
عرض

DAO — Data Access Object

نمط DAO

Repository

نمط Repository

Big ideaالفكرة الكبرى The Business Logic talks to the Repository. The Repository talks to one or more DAOs. Each DAO talks to one table through an SQL Connector. منطق العمل يحادث Repository. والـ Repository يحادث DAOs. وكل DAO يحادث جدولًا واحدًا عبر SQL Connector.
Program getStudentId() printCourses() StudentCoursesRepo + studentDAO + coursesDAO + enrollmentDAO + getStudentCourses(int) StudentDAO + sqlConnector + method() CoursesDAO + sqlConnector + method() EnrollmentDAO + sqlConnector + method() student table course table enrollment table SQL Connector + connect() + disconnect() BUSINESS REPOSITORY DAOs TABLES

Factory Method (Creational)

نمط Factory Method (إنشائي)

Definitionالتعريف Provide an interface for creating objects in a superclass, but allow subclasses to alter the type of objects created. يوفّر واجهة لإنشاء الكائنات في كلاس أعلى، لكنه يسمح للكلاسات الفرعية بتغيير نوع الكائنات المُنشَأة.

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 يُخفي تفاصيل الإنشاء ويعيد الكائنات عبر واجهة موحّدة (المنتج).

Repository getAllStudentsCourse Factory createDAO(): IDAO «interface» IDAO insert() update() CourseDAO StudentDAO Enrollment DAO Factory Method Pattern Repository asks Factory; Factory returns an IDAO; client never knows the concrete type.

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"

سلوكي · "كائن يتغيّر سلوكه كأنه غيّر صنفه"

Definitionالتعريف State is a behavioral pattern that lets an object alter its behavior when its internal state changes. It appears as if the object changed its class. State نمط سلوكي يسمح لكائن بتغيير سلوكه عند تغيّر حالته الداخلية، فيبدو كما لو أنه غيّر صنفه.

Coffee Machine Example

مثال: ماكينة القهوة

A smart coffee machine has 3 actions: insertMoney(), selectCoffee(), serveCoffee() — but their meaning depends on the current state.

ماكينة قهوة ذكية بثلاث عمليات: insertMoney() و selectCoffee() و serveCoffee() — لكن المعنى يختلف بحسب الحالة الحالية.

Idle / خامل
Selecting / اختيار
Serve / تقديم

The Pattern Structure

بنية النمط

Client CoffeeMachine «Context» - state: IState + changeState() + insertMoney() + selectCoffee() + serveCoffee() «interface» IState + insertMoney() + selectCoffee() + serveCoffee() IdleState + insertMoney() + selectCoffee() + serveCoffee() SelectingState + insertMoney() + selectCoffee() + serveCoffee() ServeState + insertMoney() + selectCoffee() + serveCoffee()

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
State vs. Strategy State مقابل Strategy Both use composition. Strategy: client picks a strategy and they don't know each other. State: states know each other and can trigger transitions to other states. كلاهما يستخدم التكوين (composition). Strategy: العميل يختار الاستراتيجية، والاستراتيجيات لا يعرفن بعضهن. State: الحالات تعرف بعضها وتستطيع طلب الانتقال بين بعضها البعض.

06 · LECTURE Decorator Design Pattern نمط Decorator

Structural · "Wrapping" objects to add behavior

هيكلي · "تغليف" الكائنات لإضافة سلوك

Definitionالتعريف A structural pattern that lets you dynamically add behavior to individual objects without changing other objects of the same class. Uses decorator classes that wrap concrete components. نمط هيكلي يسمح لك بإضافة سلوك ديناميكياً إلى كائنات بعينها دون التأثير على بقية كائنات الكلاس نفسه. يعتمد على كلاسات decorator تقوم بـتغليف المكونات الملموسة.

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

بنية النمط

Client «interface» Notifier + send(message) EmailNotifier "the base behavior" «abstract» NotifierDecorator # wrappee : Notifier + send() → wrappee.send() wraps SMSNotifier FacebookNotifier SlackNotifier

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: ...
The 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

السؤال الأول — اختيار من متعدد

Q1.1 · 1 mark

Which creational pattern ensures a class has only one instance and provides a global access point?

أي نمط إنشائي يضمن أن للكلاس نسخة وحيدة ويوفّر نقطة وصول عامة لها؟

  • AFactory Method
  • BProxy
  • CSingleton
  • DDecorator
Answer: C — Singleton الإجابة: C — Singleton

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 يضيف سلوكًا.

Q1.2 · 1 mark

Which OOP pillar is primarily applied in the Strategy pattern?

أي ركن من أركان OOP يُطبَّق أساساً في نمط Strategy؟

  • APolymorphism
  • BInheritance
  • CEncapsulation
  • DAbstraction
Answer: A — Polymorphism الإجابة: A — Polymorphism

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 فهو ما يُشغّل الاستدعاء.)

Q1.3 · 1 mark

The Template Method pattern is based on:

نمط Template Method يعتمد على:

  • AInheritance
  • BAggregation
  • CDecomposition
Answer: A — Inheritance الإجابة: A — Inheritance

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 علامات)

Q2 · Given code
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)

Dependency Inversion Principle (DIP) مبدأ عكس التبعيات (DIP)

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 (حقن التبعية).

UserRepository - conn : IDbConnection + SaveUser(name) «interface» IDbConnection + Connect() + Execute(q) SqlConnection MongoConnection Refactored Design (DIP applied)
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 مباشرة.

Hero - name : string - attack : IAttackStrategy + run() + jump() + attack() «uses» AttackFactory + create(type) : IAttackStrategy «creates» «interface» IAttackStrategy + attack() MeleeAttack + knife RangedAttack + bow + arrow MagicalAttack + wand
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 — سطر واحد لكل مبدأ

·PrincipleOne-linerالمبدأباختصار
SSingle ResponsibilityOne reason to change.المسؤولية الواحدةسبب واحد للتغيير.
OOpen / ClosedOpen to extend, closed to modify.مفتوح / مغلقمفتوح للتوسعة، مغلق على التعديل.
LLiskov SubstitutionSubtype must keep parent's promise.استبدال ليسكوفالكلاس الفرعي يحفظ وعد الأب.
IInterface SegregationMany small interfaces beat one fat interface.فصل الواجهاتواجهات صغيرة أفضل من واحدة ضخمة.
DDependency InversionDepend on abstractions, not concretions.عكس التبعياتاعتمد على التجريد لا على الملموس.

Patterns — When to Use Each

الأنماط — متى تستخدم كل واحد

PatternFamilyUse when…النمطاستخدمه عندما…
SingletonCreational …you need exactly one shared instance (logger, config). Singleton…تحتاج نسخة وحيدة مشتركة (logger، config).
Factory MethodCreational …you want to create objects without binding to concrete classes. Factory Method…تريد إنشاء كائنات دون ربط بالكلاسات الملموسة.
StrategyBehavioral …multiple algorithms can be swapped at runtime by the client. Strategy…خوارزميات متعددة يمكن تبديلها وقت التشغيل من العميل.
StateBehavioral …an object's behavior depends heavily on its current state and changes between states. State…سلوك الكائن يعتمد بشدة على حالته الحالية ويتغيّر بين الحالات.
Template MethodBehavioral …you want a fixed algorithm skeleton with overridable steps (uses inheritance). Template Method…تريد هيكل خوارزمية ثابت مع خطوات قابلة للتعديل (يستخدم الوراثة).
DecoratorStructural …you want to add behavior to individual objects dynamically by wrapping them. Decorator…تريد إضافة سلوك ديناميكي لكائنات بعينها عن طريق تغليفها.
DAOStructural …you need to encapsulate raw DB access for a single table/entity. DAO…تحتاج تغليف الوصول الخام لقاعدة البيانات لجدول واحد.
RepositoryStructural …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

PatternMechanismWho picks the variation?النمطالآليةمن يختار التنوّع؟
StrategyCompositionClient (explicitly) StrategyCompositionالعميل (صراحةً)
StateCompositionThe state objects themselves StateCompositionالحالات نفسها
DecoratorComposition (wrapping)Client builds the wrap stack DecoratorComposition (تغليف)العميل يبني سلسلة التغليف
Template MethodInheritanceSubclass (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) يحمل الحالة ويمرّر إليها كل استدعاء.