Логика проверки значений внутри или снаружи класса? - PullRequest
0 голосов
/ 06 декабря 2009

Возьмите этот класс скелета, который кто-то хочет заполнить, чтобы получать потоки RSS на ряде веб-сайтов:

public class RSSStream extends Thread {

    public RSSStream(String rssStreamName,String rssURL,int refreshTime){
        // constructor code goes here
    }
}

Теперь давайте рассмотрим, что refreshTime должно быть больше нуля и что rssURL должен быть действительным http-адресом.

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

Итак, вот пара вопросов по теме:

  • Почему некоторые классы навязывают метод getInstance () в сочетании с тем, что, вероятно, является закрытым конструктором? Если я хорошо помню, одним примером был бы GregorianCalendar.
  • В каких случаях вы бы использовали этот же подход?
  • В большинстве случаев в вашем конструкторе есть логика проверки?
  • Если это так, применяете ли вы это или нет к классам в стиле Entity, используемым в контексте постоянства модели предметной области?

Все ваши ответы приветствуются. Будет интересно получить четкое представление о наиболее распространенной практике.

Ответы [ 6 ]

3 голосов
/ 06 декабря 2009

Несколько самых распространенных вещей:

  • Если вы используете FactoryMethod для построения сложных объектов, у вас обычно будет частный конструктор, и вам потребуется создание экземпляра через фабрику. Это поддерживает переключение стратегий строительства с завода.

  • Самым понятным для меня было бы создание пользовательского (и, надеюсь, информативного) исключения в конструкторе, если создание экземпляра не может произойти::

    публичный класс Person {

        public Person(Integer id, String name) throws InvalidPersonException
             if (name==null) throw new InvalidPersonException("You cant have a person without a name");
             ...
    
  • Это может создать беспорядок в объектах персистентности сущности, главным образом потому, что вы хотите, чтобы эти объекты были свободны от логики, и потому что инфраструктура должна справиться с этим для вас - например, если у вас есть bean-компонент, содержащий (id, name) в hibernate, и вы пытаетесь сохранить его в таблице с именем, которое должно быть ненулевым, то ошибки, которую выдает db или из вашей конфигурации, должно быть достаточно.

2 голосов
/ 06 декабря 2009

Конструкторы, которым необходимо проверить свои аргументы, обычно выдают IllegalArgumentException, если проверка не удалась. Когда конструктор выдает исключение, больше не нужно беспокоиться об «наполовину инициализированном» объекте.

2 голосов
/ 06 декабря 2009

В этом конкретном случае я бы просто проверил аргумент в конструкторе и выдал исключительную ситуацию IllegalArgumentException с описательным сообщением об ошибке. Объект не будет создан, и вызывающий код должен быть восстановлен.

Вы можете сделать это и в методе getInstance (). Одна из причин использования getInstance () заключается в том, что если экземпляры очень разделяемы, чтобы сократить количество создаваемых вами объектов. Например, если у вас может быть несколько объектов RSSStream с одним и тем же URL-адресом, вы можете настроить getInstance () для совместного использования этих экземпляров. (Предполагается, что экземпляры неизменны.)

Есть также шаблон Builder. У вас есть вложенный внутренний класс с именем RSSStream.Builder и вы говорите что-то вроде:

RSSStream rss = new RSSStream.Builder.build(url)
                                     .name("stack overflow")
                                     .refreshTime(2)
                                     .build();

Этот шаблон делает ваш клиентский код более информативным, а также гарантирует, что вы никогда не создадите RSSStream в недопустимом состоянии (методы конструктора генерируют исключение IllegalArgumentException). Строитель достаточно гибок, чтобы заменить всех ваших общедоступных конструкторов.

Обычно я использовал IllegalArgumentException, выбрасывая его из конструктора или метод проверки (чтобы отделить код проверки ошибок от нескольких конструкторов). Я начал использовать метод Builder для своих более важных общедоступных API-интерфейсов, и он мне действительно нравится.

Вы, безусловно, можете использовать эти приемы в ваших классах модели предметной области.

2 голосов
/ 06 декабря 2009
  • Я прежде всего видел и использовал статический getInstance() и приватный конструктор только для использования шаблона Singleton. Однако абстрактный класс Java Calendar использует этот метод не для Singleton, а для создания реализации по умолчанию (григорианской) с часовым поясом и локалью по умолчанию. Возможно, это сделано потому, что Calendar является абстрактным и не может быть создан. GregorianCalendar на самом деле имеет публичные конструкторы.
  • В большинстве случаев я бы просто использовал открытый конструктор и методы установки без аргументов и помещал логику проверки и создание исключений в методы установки. Я часто использую инъекцию зависимостей Spring, а аннотация @Required позволяет контейнеру выдавать исключение, если не установлены все обязательные атрибуты.
  • Я не применяю такого рода логику в объектах сущностей, я стараюсь не использовать всю логику для простоты и делать их строго POJO.
2 голосов
/ 06 декабря 2009

Если ваш конструктор выдает исключение, ссылка на ваш объект не возвращается, поэтому объект можно сразу же собрать мусором. Таким образом, вы не тратите память. Я думаю, что это правильное место для проверки, когда вы создаете объекты, особенно неизменяемые.

getInstance () - это фабричный метод, который возвращает экземпляр подкласса. Вы используете это, когда возвращаете другой подкласс в зависимости от обстоятельств. Например, Calendar.getInstance () возвращает GregorianCalendar в моей локали, но он может вернуть другую реализацию, если настройки моей локали отличаются.

Для различных шаблонов для создания объектов, проверьте http://en.wikipedia.org/wiki/Creational_pattern

Надеюсь, это поможет

2 голосов
/ 06 декабря 2009

Если проверка значения, которую вам нужно сделать, может оставить экземпляр объекта в поврежденном состоянии, то вам следует подумать о создании фабрики для генерации ваших экземпляров. Это позволит вам вызвать исключение в случае, если переданные аргументы недопустимы.

Если, однако, ваш объект может быть «исправлен» в конструкторе со значениями по умолчанию в случае неудачной проверки, тогда используйте значения по умолчанию, чтобы предоставить вызывающей стороне объект, который бесполезен, но не поврежден.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...