Wariacje z datą

0

Mam zadanie, które polega na wykonaniu klasy Data (u mnie DateExample)

  • przechowującej dzień, miesiąc i rok danej daty (u mnie data urodzin);
  • klasa powinna chronić swoje pola i zapewnić niezmienność daty;
  • data powinna mieć domyślny konstruktor ustawiający bieżącą datę i konstruktor z trzema argumentami;
  • klasa powinna mieć zmienne dla wszystkich pól, ma gettery i setery;
    klasa ma metodę getMonthName(int month) która dla danego miesiąca zwraca nazwę w formie skróconej np. JAN czy FEB;
  • klasa posiada metodę toString formatującą napis do postaci DD MMM RRR

Wszystko starałem się zrobić wg swojej (na razie jeszcze prymitywnej) wiedzy.
Proszę jednak o takie krytyczne spojrzenie i wytknięcie błędów z propozycją na lepszy kod.
Może też wszystkiego dobrze nie zrozumiałem...
Będę wdzięczny za pomoc.

package MyDate;

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Scanner;

class DateExample {
    int day;
    int month;
    int year;

    DateExample() {
    }

    DateExample(int day, int month, int year) {
        this.day = day;
        this.month = month;
        this.year = year;
    }

    @Override
    public String toString() {
        return "The date of my birthday:  " + day + "/" + getMonthName(month) + "/" + year;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getDay() {
        return day;
    }

    public int getMonth() {
        return month;
    }

    public int getYear() {
        return year;
    }

public static void DateNow () {
    GregorianCalendar calendar = new GregorianCalendar();
    SimpleDateFormat formater=new SimpleDateFormat("dd MMMM yyyy");
    StringBuffer date2 = new StringBuffer("");
    Date now = calendar.getTime();
    System.out.println(formater.format(now, date2, new FieldPosition(DateFormat.DATE_FIELD)));

}

    public static String getMonthName(int month) {
        String[] stringMonth = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
        return stringMonth[month];
    }
}

public class DateEx {
    public static void main(String[] args) {
        DateExample date = new DateExample(01, 9, 1970);
        System.out.println(date.toString());

        DateExample date2 = new DateExample();
        date2.DateNow();

        Scanner input = new Scanner(System.in);
        DateExample date1 = new DateExample();
        System.out.println("Enter the date: ");
        System.out.println("Day: ");
        int d = input.nextInt();
        System.out.println("Month: ");
        int m = input.nextInt();
        System.out.println("Year: ");
        int y = input.nextInt();
        date1.setDay(d);
        date1.setMonth(m);
        date1.setYear(y);
        System.out.println("The date is: ");
        System.out.println(date1.getDay() + "/"+ DateExample.getMonthName(date1.getMonth()-1) +"/"+ date1.getYear());
    }
}
1

To coś nie tak, w jednym miejscu piszesz, że klasa powinna zapewnić niezmienność daty, w innym, że ma mieć settery. W dodatku można w twojej klasie zrobić sobie datę np. 45.45.1000, albo datę np. 29.02.2019. Zastanów się co się stanie jak wywołasz toString() lub getMonthName() dla daty, której miesiąc jest większy od 11? W klasie operujesz na miesiącach numerowanych od 0, to mało intuicyjne, każdemu styczeń kojarzy się z 1 a nie 0 itd.

Z punktu widzenia wymagań to do poprawy:

  1. konstrukt bezparametrowy, który nic nie robi a powinien to co masz w metodzie statycznej DateNow() plus wywołać konstruktor z trzema argumentami,
  2. w konstruktorze z trzema argumentami powinna być walidacja daty, co wymaga liczenia lat przestępnych, tym samym załatwisz sprawę kontroli indeksów do stringMonth.
  3. stringMonth możesz też zrobić jako prywatne statyczne finalne pole klasy,
  4. pola masz z dostępem pakietowym i klasa też, więc w takiej postaci nie ma żadnej ochrony pól, ustaw te pola jako prywatne
  5. settery są do wyrzucenia, kontrola poprawności w setterach nic nie da, jeśli nie znasz całej daty. Lepiej już robić jedną metodę z trzema argumentami do zmiany całej daty i wtedy sprawdzać, czy jest poprawna
1

Na początek off-top, słowo java pisz po znaczniku otwierającym, a nie po zamykającym.

  1. Klasa nie chroni swoich pól, one powinny być private
private int day;
  1. Brak konstruktora domyślnego
public DataExample()
{
     GregorianCalendar today = new GregorianCalendar();
     this.day = today.get(DAY_OF_MONTH);
     ...
}
  1. Metoda toString() nie spełnia warunków: poprzedza datę napisem i źle formatuje.
    4. Metoda getMonthName nie może być static. Różne daty mają różne miesiące.
0

Tak, macie Państwo rację, że w tym zadaniu niektóre podpunkty są sprzeczne i moim zdaniem trzeba stworzyć kilka wariantów, co nieudolnie próbowałem zrobić.
A z tym konstruktorem domyślnym to próbowałem coś zrobić i data wychodziła mi 0-JAN-0, dlatego wykasowałem tam wszystko. Jak wrócę do domu to spróbuję to rozwiązanie przesłane przez Państwa. Z pewnością zadziała, bo ja to robiłem nieco inaczej...
Bardzo dziękuję za pomoc!

0
cs napisał(a):

To coś nie tak, w jednym miejscu piszesz, że klasa powinna zapewnić niezmienność daty, w innym, że ma mieć settery. W dodatku można w twojej klasie zrobić sobie datę np. 45.45.1000, albo datę np. 29.02.2019. Zastanów się co się stanie jak wywołasz toString() lub getMonthName() dla daty, której miesiąc jest większy od 11? W klasie operujesz na miesiącach numerowanych od 0, to mało intuicyjne, każdemu styczeń kojarzy się z 1 a nie 0 itd.
****Czy wpisanie w konstruktorze:

this.month = month-1;

jest wystarczające?

Z punktu widzenia wymagań to do poprawy:

  1. konstrukt bezparametrowy, który nic nie robi a powinien to co masz w metodzie statycznej DateNow() plus wywołać konstruktor z trzema argumentami,
  2. w konstruktorze z trzema argumentami powinna być walidacja daty, co wymaga liczenia lat przestępnych, tym samym załatwisz sprawę kontroli indeksów do stringMonth.
    ****Czy wystarczyłoby w ciele main wprowadzić takie ogranicznenie:
if (d > 31 || d<1) System.out.println("Invalid date!");
        else if ((m == 4 && d > 30) || (m == 6 && d > 30) || (m == 9 && d > 30) || (m == 11 && d > 30))
            System.out.println("Invalid date!");
        else if ((m == 2 && d> 28) && ((y % 4 != 0 || y % 100 == 0) && (y % 400 != 0)))
            System.out.println("There isn\'t a leap year!");
        else {
            date3.setDay(d);
            date3.setMonth(m);
            date3.setYear(y);
            System.out.println("The date is: ");
            date3.getDate();
        }```
> 3. `stringMonth` możesz też zrobić jako prywatne statyczne finalne pole klasy,
> 4. pola masz z dostępem pakietowym i klasa też, więc w takiej postaci nie ma żadnej ochrony pól, ustaw te pola jako prywatne
> 5. settery są do wyrzucenia, kontrola poprawności w setterach nic nie da, jeśli nie znasz całej daty. Lepiej już robić jedną metodę z trzema argumentami do zmiany całej daty i wtedy sprawdzać, czy jest poprawna
0

Czy wpisanie w konstruktorze:
this.month = month-1;
jest wystarczające?

No może być, choć ja bym trzymał wewnątrz klasy month w zakresie od 1 do 12, a w metodzie getMonthName() zrobił return stringMonth[month-1];.

Czy wystarczyłoby w ciele main wprowadzić takie ogranicznenie:
int y = input.nextInt();
if ((y % 4 != 0 && y % 100 == 0) || (y % 400 != 0))
if (d==29) System.out.println("There isn't a leap year!");
date1.setDay(d);

Jeśli testowałeś dni lutego to powinno być:

if ((y % 4 != 0 && y % 100 == 0) || (y % 400 != 0)) {
  if (d == 29 && m == 2) { 
    System.out.println("There isn\'t a leap year!");
    return;
    }
}

Właściwie to powinno znaleźć się wewnątrz klasy w konstruktorze, tylko problemem jest jak ma zachować się konstruktor na niepoprawne dane. Dlatego obiekty klasy LocalDate tworzy się metodami statycznymi, które zgłaszają wyjątek na niepoprawną datę, a konstruktor jest prywatny. Ale jeszcze pewnie nie znasz wyjątków i takiej metody tworzenia obiektów. Więc na tym etapie nauki możesz zrobić testowanie poprawności poza klasą, tylko to co napisałeś to za mało, co z testowaniem miesięcy, dni itd.

Ewentualnie możesz umieścić testowanie poprawności w konstruktorze i przyjąć jakiś kontrakt np. jeśli data jest niepoprawna to obiekt zainicjuj bieżącą datą. Ostatecznie to tylko zadanie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1