المسارات
/
Java
Java
/
التمارين
/
عملاء صالون التجميل الدائمون
عملاء صالون التجميل الدائمون

عملاء صالون التجميل الدائمون

تمرين تعلّمي

مقدمة

المعدّلات الزمنية

عند العمل مع كائنات java.time مثل LocalDate، غالبًا ما تحتاج إلى إجراء تعديلات معقّدة على التواريخ، مثل إيجاد «الثلاثاء الثاني من الشهر». وبدلًا من حساب ذلك يدويًا، يمكنك استخدام TemporalAdjusters.

يوفّر صنف الأدوات المساعدة java.time.temporal.TemporalAdjusters (لاحظ حرف s في آخره) دوال static لكثير من تعديلات التواريخ الشائعة. وتُطبّق هذه التعديلات باستخدام الطريقة .with() على كائن زمني (مثل LocalDate).

Note

استخدام with(TemporalAdjuster) يُرجع نسخة جديدة ولا يحدّث النسخة الموجودة، لأن كائنات java.time غير قابلة للتغيير.

import java.time.LocalDate;
import java.time.Month;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 (a Thursday)

// Use a predefined adjuster: find the last day of the month
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
// => 2024-08-31

إليك بعض المعدّلات الأساسية المفيدة في حسابات الجدولة:

إيجاد اليوم الترتيبي في الأسبوع

استخدم dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) لإيجاد التكرار رقم n ليوم من أيام الأسبوع.

// Find the second Tuesday of August 2024
LocalDate secondTuesday = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY));
// => 2024-08-13

إيجاد أول/آخر يوم من أيام الأسبوع في الشهر

استخدم firstInMonth(DayOfWeek dayOfWeek) أو lastInMonth(DayOfWeek dayOfWeek).

// Find the last Monday of August 2024
LocalDate lastMonday = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY));
// => 2024-08-26

التعديلات النسبية (التالي/السابق)

المعدّلات مثل next() وprevious() وnextOrSame() وpreviousOrSame() تجد التكرار التالي أو السابق ليوم معيّن من أيام الأسبوع، نسبةً إلى التاريخ الحالي.

  • next()/previous(): تستبعدان التاريخ الحالي إذا طابقه.
  • nextOrSame()/previousOrSame(): تشملان التاريخ الحالي إذا طابقه.
LocalDate thursday = LocalDate.of(2024, Month.AUGUST, 15); // A Thursday

// Find the next Thursday (exclusive)
LocalDate nextThursday = thursday.with(TemporalAdjusters.next(DayOfWeek.THURSDAY));
// => 2024-08-22

// Find the next Thursday (inclusive) - returns the same date
LocalDate nextOrSameThursday = thursday.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY));
// => 2024-08-15

// Find the previous Monday (exclusive)
LocalDate previousMonday = thursday.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
// => 2024-08-12

المعدّلات المخصّصة

TemporalAdjuster واجهة وظيفية، لذا يمكنك كتابة معدّل خاص بك على هيئة تعبير لامدا يستقبل الكائن الزمني المطلوب تعديله ويُرجع الكائن بعد التعديل. ويُطبَّق باستخدام .with() تمامًا مثل المعدّلات المعرّفة مسبقًا، ويمكنه أن يستخدمها داخليًا.

import java.time.temporal.TemporalAdjuster;

// An adjuster that moves a weekend date to the following Monday
TemporalAdjuster skipWeekend = temporal -> {
    DayOfWeek day = DayOfWeek.from(temporal);
    if (day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY) {
        return temporal.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
    }
    return temporal;
};

LocalDate saturday = LocalDate.of(2024, Month.AUGUST, 17);
LocalDate monday = saturday.with(skipWeekend);
// => 2024-08-19

إن استخدام هذه المعدّلات من صنف TemporalAdjusters يبسّط كثيرًا مهام التعامل مع التواريخ.

التعليمات

يسير صالون التجميل في نيويورك الذي ساعدته في تمرين «الحجز من أجل الجمال» على ما يرام، وقد أصبح الكثير من عملائه من العملاء الدائمين. فبدلًا من حجز كل زيارة على حدة، لدى العميل الدائم اتفاق ثابت: «كل ثلاثاء ثانٍ»، «آخر جمعة في الشهر»، وهكذا. وقد طلبت منك صاحبة الصالون مساعدًا يحسب التواريخ الكامنة وراء هذه الاتفاقات، وكذلك تواريخ الروتين الشهري للصالون نفسه.

1. إيجاد الموعد الثابت لعميل دائم

نفّذ الطريقة SalonCalendar.standingAppointment() التي تأخذ سنة وشهرًا ورقم المرة (1 للمرة الأولى، و2 للمرة الثانية، وهكذا) ويومًا من أيام الأسبوع. وهي تُرجع تاريخ تلك المرة من يوم الأسبوع داخل الشهر:

SalonCalendar calendar = new SalonCalendar();
calendar.standingAppointment(2024, Month.AUGUST, 2, DayOfWeek.TUESDAY);
// => LocalDate.of(2024, 8, 13)

2. إيجاد موعد آخر الشهر لعميل دائم

يفضّل بعض العملاء الدائمين المرة الأخيرة من يومهم في الشهر. نفّذ الطريقة SalonCalendar.lastAppointment() التي تأخذ سنة وشهرًا ويومًا من أيام الأسبوع، وتُرجع تاريخ آخر مرة من ذلك اليوم من أيام الأسبوع داخل الشهر:

SalonCalendar calendar = new SalonCalendar();
calendar.lastAppointment(2024, Month.AUGUST, DayOfWeek.FRIDAY);
// => LocalDate.of(2024, 8, 30)

3. إيجاد أقرب يوم متاح لعميل بدون موعد

يطلب أحد العملاء عند مكتب الاستقبال «السبت القادم». وإذا كان اليوم الذي يسأل فيه هو السبت نفسه، فهو يعني ذلك اليوم ذاته. نفّذ الطريقة SalonCalendar.nextAvailable() التي تأخذ تاريخًا ويومًا من أيام الأسبوع، وتُرجع أول تاريخ في التاريخ المعطى أو بعده يوافق ذلك اليوم من أيام الأسبوع:

SalonCalendar calendar = new SalonCalendar();
calendar.nextAvailable(LocalDate.of(2024, 8, 15), DayOfWeek.SATURDAY);
// => LocalDate.of(2024, 8, 17)
calendar.nextAvailable(LocalDate.of(2024, 8, 17), DayOfWeek.SATURDAY);
// => LocalDate.of(2024, 8, 17)

4. إيجاد يوم إقفال الدفاتر

يُقفل الصالون دفاتره في آخر يوم من كل شهر. غير أن الصالون مغلق في عطلات نهاية الأسبوع، فإذا وافق آخر يوم في الشهر يوم سبت أو أحد، أُقفلت الدفاتر يوم الجمعة الذي قبله. نفّذ الطريقة SalonCalendar.bookkeepingDay() التي تأخذ سنة وشهرًا، وتُرجع يوم إقفال الدفاتر في ذلك الشهر:

SalonCalendar calendar = new SalonCalendar();
calendar.bookkeepingDay(2024, Month.SEPTEMBER);
// => LocalDate.of(2024, 9, 30)
calendar.bookkeepingDay(2024, Month.AUGUST);
// => LocalDate.of(2024, 8, 30)

5. إعادة استخدام قاعدة عطلة نهاية الأسبوع ليوم الرواتب

يتقاضى الموظفون رواتبهم في الخامس عشر من كل شهر، وبنفس قاعدة عطلة نهاية الأسبوع: فإذا وافق الخامس عشر يوم سبت أو أحد، كان يوم الرواتب هو الجمعة الذي قبله. بدلًا من كتابة القاعدة مرة ثانية، حوّلها إلى مُعدِّل قابل لإعادة الاستخدام.

نفّذ الطريقة SalonCalendar.precedingWorkday() التي تُرجع TemporalAdjuster يترك أيام الأسبوع كما هي، ويعيد يوم السبت أو الأحد إلى يوم الجمعة الذي قبله. ثم نفّذ الطريقة SalonCalendar.payday() التي تأخذ سنة وشهرًا، بالاستعانة بذلك المُعدِّل:

SalonCalendar calendar = new SalonCalendar();
LocalDate.of(2024, 6, 15).with(calendar.precedingWorkday());
// => LocalDate.of(2024, 6, 14)
calendar.payday(2024, Month.JUNE);
// => LocalDate.of(2024, 6, 14)
calendar.payday(2024, Month.AUGUST);
// => LocalDate.of(2024, 8, 15)

لا تتردد في العودة واستخدام المُعدِّل في bookkeepingDay() أيضًا.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Java Exercism

مستعد لبدء عملاء صالون التجميل الدائمون؟

سجّل في Exercism لتتعلّم وتتقن Java عبر 27 مفهومًا159 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.