Класс date для Java - переключатели и IFS в конструкторе


Я новичок, у меня задание написать класс дата (как часть более крупного проекта). на мой вопрос мне сосредоточиться на конструктор. вот некоторые справочная информация: даются рекомендации, что дата не будет действителен и на следующие переменные экземпляра ожидать это входной диапазон: день - целое число 1-31 месяц - число 1-12 год - целое число, 4 цифры года.

теперь, если введен неверный день/месяц/год или дата недействительным (например, 31.2.2010), то объект будет создан с дата 1.1.2000.

это код, который я придумал и он компилируется и вроде работает нормально.

public class Date
{
    private int _day;
    private int _month;
    private int _year;


    public Date (int day, int month, int year)  
    {
        switch (month)
        {
            case 1:                
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12: if ((day>0 && day<32) && (year>999 && year<10000))
            {
                _day=day;
                _month=month;
                _year=year;           
            }
            else
            {
                _day=1;
                _month=1;
                _year=2000;
            }
            break;

            case 4:
            case 6:
            case 9:
            case 11: if ((day>0 && day<31) && (year>999 && year<10000))
            {
                _day=day;
                _month=month;
                _year=year;           
            }
            else
            {
                _day=1;
                _month=1;
                _year=2000;
            }
            break;

            case 2: if (leap(year))
            {
                if ((day>0 && day<30) && (year>999 && year<10000))
                {
                    _day=day;
                    _month=month;
                    _year=year;           
                }
                else
                {
                    _day=1;
                    _month=1;
                    _year=2000;
                }
                break;
            }

            else
            {
                if ((day>0 && day<29) && (year>999 && year<10000))
                {
                    _day=day;
                    _month=month;
                    _year=year;           
                }
                else
                {
                    _day=1;
                    _month=1;
                    _year=2000;
                }
                break;
            }
        }
    }

    /** check if leap year */
    private boolean leap (int y)  
    {
        return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
    }
}

вот мои вопросы:

  1. Это хорошо, чтобы положить все, что код в конструкторе? это существенно влияет на время обработки или вызвать ошибку? есть ли альтернатива, если его проблемы?

  2. Любая часть кода может считаться плохой практикой? такие как переключатели и IFS? Я не чувствую себя уверенным с этой сборки, несмотря на это работает нормально...

извините за неудобства, вмятины и такие, 1-й пост :(



Комментарии
4 ответа

Получая ваш класс составление и работа-это достижение само по себе. Так что не позволяйте мои комментарии разочаровать вас, но рассматривайте их в качестве подсказки для следующего этапа обучения.

Время обработки

Не беспокойтесь об этом, пока вы действительно возникнуть проблемы с производительностью. Даже опытные программисты часто терпят неудачу при попытке предсказать производительность своего кода. Если вы столкнулись с проблемами производительности, то научитесь использовать инструменты анализа, как "профайлерами". Но скорее всего, вы не будете нуждаться в них в течение следующих нескольких лет.

Код в конструктор

Это хорошо делать проверки в конструкторах. Но вы правы, читаемость конструктора страдает от его длины. Ключ к читабельности является внедрение хороших абстракций, а не писать длинный код, как вы уже сделали с leap() метод. Пишу monthLength(int year, int month) метод и используя, что в конструкторе, вы можете избавиться от самых переключателя/если заявления.

Недопустимые даты

Вы решили создать 01.01.2000 дата в случае поврежденных элементов. Профессионалы вместо throw в IllegalArgumentException.

Как Java для начинающих, вполне вероятно, что вы еще не узнали о концепции исключения, но это важная вещь, элегантный способ сказать кому-то, кто хочет построить например 31.2.2010 дата, что вы не можете дать ему эту дату, так как его не существует. Как Caller конструктора или метода, я всегда хотите быть в курсе успехов или неудач, и исключения-это хороший способ сделать это.

2
ответ дан 22 марта 2018 в 08:03 Источник Поделиться

Во-первых, ваш код не проверяет месяц. Если месяц параметр значение вне диапазона 1-12, тогда все три поля _day, _month и _year будет инициализирован к их значениям по умолчанию 0.

Теперь, причина, вы не убеждены в коде может быть что он содержит много повторяющегося кода, а именно проверка и присвоение трех областях вашего Date класс. Вы могли бы начать, чтобы исправить эту проблему, поставив код для инициализации Date экземпляр по умолчанию значение 1.1.2000 только в одном месте, вместо того, чтобы повторять его для каждого возможного случай недопустимую дату. Способ сделать это было бы создать статический вспомогательный метод, который проверяет входные даты, и если этот метод возвращает falseт. е. если дата является недействительным, то ваш Date инициализируется 1.1.2000.

private static boolean isValidDate(int day, int month, int year) {
if (year < 1000 || year > 9999) {
return false;
}
if (month < 1 || month > 12) {
return false;
}
if (day < 1) { //this condition is independent of the month
return false;
}
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return day <= 31;
case 4:
case 6:
case 9:
case 11:
return day <= 30;
default:
/*
we have already ascertained that month lies between 1 and 12, so
month must be 2 now
*/
assert month == 2;
return leap(year) ? day <= 29 : day <= 28;
}
}

Это, вероятно, не будет компилироваться, если вы добавить его в ваш код, потому что в коде leap(int) не static и поэтому не может ссылаться из статического контекста. Однако, поскольку leap(int) не зависит от каких-либо три экземпляра переменные Dateбыло бы более целесообразным, если leap(int) были статическими, а также. Кстати, я не думаю "leap" это очень хороший способ имя, потому что это действительно не описать то, что метод делает. Более информативное название может быть "isLeapYear".

Теперь, с этим вспомогательный метод, фактический инициализации Date объект будет кусок пирога:

public Date(int day, int month, int year) {
if (isValidDate(day, month, year)) {
_day = day;
_month = month;
_year = year;
} else {
_day = 1;
_month = 1;
_year = 2000;
}
}

Наконец, если вы не намерены менять значения _day, _month и _yearвы можете сделать эти поля finalтак Date будет означает, что, один раз в Date экземпляр создается, он никогда не изменится, который может сделать много вещей, легче просто потому, что вы никогда не придется беспокоиться о возможности Date изменяемому объекту.

2
ответ дан 23 марта 2018 в 09:03 Источник Поделиться


Это хорошо, чтобы положить все, что код в конструкторе?

Конструктор должен назначить только не делать любую работу, кроме очень простые проверки, как проверка входов дляnull. Сложные проверки, которые вы делаете, должно быть сделано вне конструктора, сразу после того, как данные были введены в программу.


есть ли альтернатива, если его проблемы?

В качестве альтернативы можно создать метод фабрики , который сначала делает проверку и возвращает (действительный) предмет или бросает IllegalArgumentException как предположил Ральф Kleberhoff.

Это заводской метод может быть static метод в свой класс. Но static методы имеют свои недостатки самостоятельно. Поэтому метод фабрики, как правило, живет в фабрику класса, а не статические.

0
ответ дан 23 марта 2018 в 03:03 Источник Поделиться

подчеркивания префикс

Во-первых, я не люблю использовать символ подчеркивания в качестве префикса. Это было сделано еще в тот день, когда язь не визуально представляют переменные как переменные-члены. То же касается статических переменных или констант. Покуда вы не пишите свой код в VI, нет никаких причин для этого.

охранники

Ваши "гвардейцы" разбросаны в конструкторе (день=1 месяц=1,год=2000 деталей). Убедитесь, что переменные являются правильными первых, так вы можете быть уверены, что остальная часть кода работает.

Кроме того, пользователь не имеет обратной связи, если они передают дрянь, они просто в конечном итоге на 01.01.2000. Это очень подвержен ошибкам. Проверить первый, и бросать исключение, если параметры неверны.

И на самом деле, это не стража, но значения по умолчанию.

дублирование кода (не повторяй себя)

Я считаю year>999 && year<10000 три раза, задание по умолчанию значений в четыре раза, назначение фактических параметров в четыре раза.

В year>999 ... часть может легко быть преобразована в отдельный метод isYearValid или что-то похож.

Значения по умолчанию могут быть назначены непосредственно при объявлении переменных. Но, честно говоря, типа не должны иметь значения по умолчанию на первом месте (ИМО).

наименования / комментарии

Метод leap есть комментарий /** check if leap year. Прежде всего, это документация частного метода. Попробуйте назвать свои вещи, поэтому никто не нуждается в документации, или комментарий в любом случае. Если я кодирования в тип, и мой код завершения показывает мне leap(y: int)Я представляю, кто-то прыгает y метров в высоту (и высокого, потому что y-вертикальная ось). Как правило, методы, которые возвращают логическое, имеют is префикса. Но isLeap(y: int) не хватает, потому что дата не может прыгать. Так что иди с isLeapYear(year: int).

Небольшой и, возможно, ненужную деталь: в большинстве дата АФИ, в день обычно называется "dayOfMonth", чтобы избежать путаницы с "функции dayofyear" или "день недели".

Проверьте, как другие реализовали это

Ты далеко не первый, кто реализовал дата. И на самом деле, есть много, что может пойти не так. Вы могли бы хотеть проверить LocalDate на grepcode.com. В LocalDate из OpenJDK в более 2000 длинные очереди. Большинство это, конечно, дополнительный функционал. Но все остальное может быть интересно.

Не изобретать колесо

Скажу честно: я не вижу никаких причин не использовать уже написанный код. В LocalDate нормально, делает все, что вы хотите и даже больше. И это еще сложнее (лучше комплексные), чем можно было бы подумать. Я был бы несколько разочарован, если бы мне пришлось писать и особенно поддерживать код, который поставляется с JDK.

Ладно, если честно В2: работа с java.util.Date перед JDK 1.8 (я думаю?) была огромная боль. Люди привыкли, что фантазии в JSR-аддон для 1.7 или JodaTime. И перенести эти вещи - особенно если ваше программное обеспечение поддерживает несколько часовых поясов в рамках одной виртуальной машины и один backend - не очень экономической (и довольно страшные). Но они сделали действительно хорошую работу в 1.8, ИМО.

0
ответ дан 24 марта 2018 в 01:03 Источник Поделиться