Должен ли класс проверять себя или создавать другой класс для его проверки?
Скажем, у меня есть класс вроде:
class NavigationData
{
float roll;
float pitch;
double latitude;
double longitude;
}
и если я хочу создать метод:
const bool validate() const;
который в основном проверяет, содержат ли 4 поля допустимые значения.
Должен ли validate() быть частью класса NavigationData или создавать что-то вроде NavigationDataValidator, содержащего метод validate (const NavigationData &).
Я просто даю простой пример, очевидно, что мой настоящий класс намного сложнее этого. Я ищу хорошие принципы OO.
По другому: с помощью метода, как мы узнаем, должен ли он принадлежать классу или должен принадлежать отдельному классу?
Ответы
Ответ 1
Обычно это ответственность за класс, чтобы гарантировать, что он поддерживает логически последовательное и действительное внутреннее состояние. Например, Person
может иметь конструктор, который требует как первого, так и последнего имени, если операции с Person
бессмысленны без этих данных.
Однако "логически последовательная и действительная" отличается от "имеет смысл в домене", поэтому иногда ответственность внешнего класса заключается в обеспечении соблюдения правил домена. Например, PersonValidator
может потребовать, чтобы Person
имел номер телефона, который находится в США. Но Person
не обязательно должен знать что-либо о том, есть ли PhoneNumber
в США.
Хорошее эмпирическое правило состоит в том, что если в дополнение к данным, уже принадлежащим классу, требуются правила состояния или домена, внешние по отношению к классу, вам нужно будет рассмотреть возможность внешней проверки. Вы также можете захотеть централизовать проверку во внешнем классе, если состояние экземпляров класса может поступать из нескольких источников (например, базы данных, веб-формы, файла и т.д.).
Ответ 2
Правильный ответ: зависит от.
Естественное место для размещения такой логики объекта находится в самом объекте. Иногда, хотя правила проверки могут зависеть от механизма правил или какого-то более крупного "фреймворка", который проверяет материал. Другая ситуация, когда вы не хотите делать валидацию внутри объекта, заключается в том, что проверка выполняется в другом уровне, слое или приложении, таком как уровень представления.
Ответ 3
Ваш класс должен быть разработан таким образом и предоставлять такие методы, которые validate() всегда верны:
- после вызова любого публичного конструктора
- до и после вызова любого общедоступного метода
- (в С++ - земля) до вызова деструктора
Такие методы validate() называются инвариантами класса и являются важной частью Design by Contract.
Ответ 4
Я бы сказал, это зависит. Если данные класса проверяются изолированно, я бы поместил этот метод в класс, но если для проверки требуется контекст, я бы создал класс проверки на основе некоторого интерфейса.
Ответ 5
В зависимости...
Иногда проверки не являются частью самого класса, но бизнес-логика и добавление ее в класс будет препятствовать повторному использованию, и поэтому использование проверяющего класса является хорошим. В противном случае класс должен иметь возможность проверять себя.
Ответ 6
Я бы сказал, что он проверяет себя до тех пор, пока действительные значения не зависят от того, что другие классы используют NavigationData.
В принципе, до тех пор, пока широта и высота тона должны всегда находиться между +/- 90 градусов, а долгота и валик всегда находятся между +/- 180 градусов, сохраните валидатор в классе.
(Кстати, как насчет заголовка?)
Ответ 7
Это зависит от контекста. Иногда ваш объект абсолютно важен внутри, но в контексте его значения неприемлемы.
Если у вас есть простой объект передачи данных, он, вероятно, не должен проверять себя.
Если у вас есть класс Domain Model, он должен выполнить некоторую проверку.
P.S. только мои личные предпочтения: isValid() вместо validate(), когда метод возвращает логическое значение.
Ответ 8
Как уже было сказано, это зависит.
Но в вашем случае я бы пошел на другое решение, создаю новый неизменный класс для геокоординат
class GeoCoordinates
{
double Latitude;
double Longitude;
}
И пусть этот класс проверяет, что широта и долгота находятся в допустимых пределах. Например, вам, вероятно, понадобятся и другие места.
class Airport
{
GeoCoordinates Location;
...
}