Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

خدمة تأجير المركبات

جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 87 من 87.

لهذا التحدي النهائي، ستقوم ببناء نظام خدمة تأجير المركبات يجمع بين جميع مفاهيم البرمجة كائنية التوجه (OOP) التي أتقنتها طوال هذه الدورة.

يجب أن يقوم نظامك بنمذجة أسطول من أنواع المركبات المختلفة. فكر في فئة Vehicle أساسية بخصائص مشتركة مثل لوحة الترخيص، والعلامة التجارية، ومعدل الإيجار اليومي. الفئات الفرعية مثل Car، و Motorcycle، و Truck يمكنها توسيع ذلك بخصائص محددة مثل عدد المقاعد، أو حجم المحرك، أو سعة الحمولة.

يمكن للواجهات (Interfaces) تحديد سلوكيات التأجير: قد تعلن واجهة Rentable عن دوال (methods) مثل rent() و returnVehicle() و calculateCost(int days). يمكن لأنواع المركبات المختلفة تنفيذ استراتيجيات تسعير بشكل مختلف، مما يجعل هذا حالة استخدام مثالية لتعدد الأشكال (polymorphism).

فكر في كيفية قيام فئة RentalAgency بإدارة الأسطول باستخدام التركيب (composition).

الاستثناءات المخصصة مثل VehicleNotAvailableException يمكنها التعامل مع الحالات الاستثنائية.

قد تقوم بتطبيق نمط المصنع (Factory pattern) لإنشاء المركبات أو استخدام الـ enums لفئات المركبات وحالة التأجير.

يختبر هذا التحدي قدرتك على تصميم نظام برمجة كائنية التوجه (OOP) كامل وجيد التنظيم. بالتوفيق!

challenge icon

التحدي

سهل

لنقم ببناء خدمة تأجير مركبات كاملة تجمع كل ما تعلمته عن البرمجة كائنية التوجه (OOP)! ستقوم بإنشاء نظام يدير أسطولاً من أنواع مختلفة من المركبات، ويتعامل مع عمليات التأجير مع التحقق المناسب من الصحة، ويستخدم نمط المصنع لإنشاء المركبات.

ستقوم بتنظيم الكود الخاص بك عبر سبعة ملفات:

  • RentalStatus.java: أنشئ enum يمثل حالة تأجير المركبة. قم بتضمين القيم AVAILABLE، و RENTED، و MAINTENANCE. أضف حقلاً خاصاً description (String)، ومنشئاً (constructor)، وطريقة getter. يجب أن يكون للقيم AVAILABLE الوصف "ready to rent"، وللقيمة RENTED الوصف "currently in use"، وللقيمة MAINTENANCE الوصف "under service".
  • VehicleNotAvailableException.java: أنشئ استثناءً مخصصاً يرث من Exception. يجب أن يقبل المنشئ رقم اللوحة (license plate) وينشئ رسالة بالتنسيق Vehicle not available: [licensePlate].
  • Rentable.java: أنشئ واجهة (interface) تحدد عمليات التأجير. صرّح عن الطرق rent() التي تعيد boolean، و returnVehicle() التي تعيد boolean، و calculateCost(int days) التي تعيد double.
  • Vehicle.java: أنشئ فئة أساسية مجردة (abstract base class) لجميع المركبات. قم بتضمين حقول خاصة لـ licensePlate (String)، و brand (String)، و dailyRate (double)، و status (RentalStatus، مهيأة بـ AVAILABLE). يأخذ المنشئ licensePlate و brand و dailyRate. قم بتضمين طرق getter المناسبة وطريقة setter للحالة. صرّح عن طريقة مجردة getVehicleType() تعيد String. قم بتنفيذ طريقة getDetails() التي تعيد "[licensePlate] [brand] ([vehicleType]) - $[dailyRate]/day - [status description]" مع تنسيق dailyRate إلى منزلتين عشريتين.
  • Car.java: أنشئ فئة ترث من Vehicle وتنفذ Rentable. أضف حقلاً خاصاً seats (int). يأخذ المنشئ licensePlate و brand و dailyRate و seats. قم بتنفيذ getVehicleType() لتعيد "Car". بالنسبة لـ rent()، إذا كانت الحالة AVAILABLE، فقم بتغييرها إلى RENTED وأعد true؛ وإلا أعد false. بالنسبة لـ returnVehicle()، إذا كانت الحالة RENTED، فقم بتغييرها إلى AVAILABLE وأعد true؛ وإلا أعد false. بالنسبة لـ calculateCost(int days)، أعد حاصل ضرب dailyRate في days.
  • Motorcycle.java: أنشئ فئة ترث من Vehicle وتنفذ Rentable. أضف حقلاً خاصاً engineCC (int). يأخذ المنشئ licensePlate و brand و dailyRate و engineCC. قم بتنفيذ getVehicleType() لتعيد "Motorcycle". قم بتنفيذ طرق Rentable بنفس طريقة Car، ولكن يجب أن تطبق calculateCost() خصماً بنسبة 10% (اضرب في 0.9).
  • RentalAgency.java: أنشئ فئة تدير أسطول المركبات باستخدام ArrayList. قم بتضمين الطرق التالية:
    • addVehicle(Vehicle vehicle) - تضيف مركبة إلى الأسطول
    • findVehicle(String licensePlate) - تعيد المركبة (Vehicle) أو null
    • rentVehicle(String licensePlate, int days) - تبحث عن المركبة، وتحاول تأجيرها (بتحويلها إلى Rentable)، وتعيد تكلفة الإيجار. ارمِ VehicleNotAvailableException إذا لم يتم العثور على المركبة أو إذا أعادت rent() القيمة false
    • returnVehicle(String licensePlate) - تبحث عن المركبة وتعيدها، وتعيد true عند النجاح
    • getAvailableVehicles() - تعيد ArrayList من المركبات التي حالتها AVAILABLE
  • Main.java: ابنِ خدمة التأجير الخاصة بك! ستتلقى سلسلة نصية من الأوامر مفصولة بفاصلة:
    • ADD_CAR:licensePlate:brand:dailyRate:seats
    • ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC
    • RENT:licensePlate:days
    • RETURN:licensePlate
    • AVAILABLE

    قم بمعالجة كل أمر واطبع ما يلي:

    • ADD_CAR/ADD_MOTORCYCLE: Added: [brand] ([vehicleType])
    • RENT: Rented [licensePlate] for [days] days - Total: $[cost] (التكلفة بمنزلتين عشريتين)، أو Error: [exception message]
    • RETURN: Returned: [licensePlate] أو Return failed: [licensePlate]
    • AVAILABLE: اطبع Available vehicles: متبوعة بتفاصيل كل مركبة متاحة في أسطر منفصلة

    بعد معالجة جميع الأوامر، اطبع --- Fleet Summary --- متبوعة بتفاصيل كل مركبة.

ستتلقى مدخلاً واحداً: سلسلة أوامر مفصولة بفاصلة.

على سبيل المثال، مع المدخل ADD_CAR:ABC-123:Toyota:50.00:5,ADD_MOTORCYCLE:XYZ-789:Honda:40.00:600,RENT:ABC-123:3,RENT:ABC-123:2,AVAILABLE,RETURN:ABC-123، سيكون مخرجك:

Added: Toyota (Car)
Added: Honda (Motorcycle)
Rented ABC-123 for 3 days - Total: $150.00
Error: Vehicle not available: ABC-123
Available vehicles:
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rent
Returned: ABC-123
--- Fleet Summary ---
ABC-123 Toyota (Car) - $50.00/day - ready to rent
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rent

يجمع هذا التحدي بين الوراثة (هيكل المركبات)، والواجهات (Rentable)، والـ enums (RentalStatus)، والاستثناءات المخصصة، وتعدد الأشكال (التعامل مع أنواع المركبات المختلفة بشكل موحد)، والتركيب (RentalAgency التي تدير المركبات) في نظام خدمة تأجير كامل!

جرّب بنفسك

import java.util.Scanner;
import java.util.ArrayList;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: إنشاء مثيل (instance) من RentalAgency
        
        // TODO: تقسيم المدخلات بواسطة الفاصلة للحصول على الأوامر الفردية
        
        // TODO: معالجة كل أمر:
        // ADD_CAR:licensePlate:brand:dailyRate:seats -> طباعة "Added: [brand] ([vehicleType])"
        // ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC -> طباعة "Added: [brand] ([vehicleType])"
        // RENT:licensePlate:days -> طباعة "Rented [licensePlate] for [days] days - Total: $[cost]" (بمنزلتين عشريتين)
        //                           أو "Error: [exception message]" في حال حدوث استثناء (exception)
        // RETURN:licensePlate -> طباعة "Returned: [licensePlate]" أو "Return failed: [licensePlate]"
        // AVAILABLE -> طباعة "Available vehicles:" متبوعة بتفاصيل كل مركبة متاحة
        
        // TODO: بعد جميع الأوامر، طباعة "--- Fleet Summary ---"
        // متبوعة بتفاصيل كل مركبة
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming