У меня есть два объекта, которые представляют «Бар / Клуб» (место, где вы пьете / общаетесь).
В одном сценарии мне нужно имя бара, адрес, расстояние, слогон
В другом сценарии мне нужно название бара, адрес, URL сайта, логотип
Итак, у меня есть два объекта, представляющих одно и то же, но с разными полями.
Мне нравится использовать неизменяемые объекты, поэтому все поля задаются из конструктора .
Один вариант - иметь два конструктора и обнулять другие поля, т.е.
class Bar {
private final String name;
private final Distance distance;
private final Url url;
public Bar(String name, Distance distance){
this.name = name;
this.distance = distance;
this.url = null;
}
public Bar(String name, Url url){
this.name = name;
this.distance = null;
this.url = url;
}
// getters
}
Мне это не нравится, так как вам придется проверять ноль, когда вы используете геттеры
В моем реальном примере первый сценарий имеет 3 поля, а второй - около 10, так что было бы очень сложно иметь два конструктора , количество полей, которые я должен был бы объявить нулевым, а затем, когда объект используется, вы не захотите Не знаю, какие Bar
вы используете, и какие поля будут нулевыми, а какие нет.
Какие еще варианты у меня есть?
Два класса называется BarPreview
и Bar
?
Какой-то тип наследования / интерфейс?
Что-то еще, что удивительно?
Bar
в качестве идентификатора!You should only ask practical, answerable questions based on actual problems that you face.
и это именно то, что здесь происходитОтветы:
Мои мысли:
«Бар», представленный в вашем домене, содержит все, что может понадобиться в любом месте: имя, адрес, URL, логотип, слоган и «расстояние» (я полагаю, из местоположения запрашивающей стороны). Следовательно, в вашем домене должен быть один класс «Bar», который является официальным источником данных для одного бара, независимо от того, где эти данные будут использоваться позже. Этот класс должен быть изменяемым, чтобы при необходимости можно было вносить изменения в данные панели и сохранять их.
Однако у вас есть два места, в которых нужны данные этого объекта Bar, и им обоим нужно только подмножество (и вы не хотите, чтобы эти данные были изменены). Обычный ответ - «объект передачи данных» или DTO; POJO (обычный старый Java-объект), содержащий неизменяемые свойства get. Эти DTO могут быть получены путем вызова метода основного объекта домена Bar: "toScenario1DTO ()" и "toScenario2DTO ()"; результаты - гидратированный DTO (это означает, что вам нужно использовать только длинный и сложный конструктор в одном месте).
Если вам когда-нибудь нужно было отправить данные обратно в основной класс домена (чтобы обновить его; какой смысл в данных, если вы не можете изменить их по мере необходимости, чтобы отразить текущее состояние реального мира?), Вы можете создать один из DTO или используйте новый изменяемый DTO и передайте его обратно классу Bar с помощью метода updateFromDto ().
РЕДАКТИРОВАТЬ: предоставить пример:
Классы Address, Distance и Url должны быть либо неизменяемыми, либо при использовании в DTO их следует заменять неизменяемыми аналогами.
источник
Если вы заботитесь только о подмножестве свойств и хотите убедиться, что они не перепутаны, создайте два интерфейса и используйте их для связи с вашим базовым объектом.
источник
Bar
классаЗдесь может быть полезен Образец Строителя (или что-то близкое к нему).
Наличие неизменных объектов - замечательная вещь, но реальность такова, что с Reflection в Java нет ничего действительно безопасного ;-).
источник
HawaiianPizzaBuilder
работает, потому что значения, которые ему нужны, жестко закодированы. Однако как вы можете использовать этот шаблон, если значения извлекаются и передаются в конструктор? УHawaiianPizzaBuilder
все еще были бы все методы получения, которыеSpicyPizzaBuilder
имеют настолько нулевое, возможно. Если вы не объедините это с @JarrodsNull Object Pattern
. Пример кода, с помощьюBar
которого вы получите свою точку зренияКлючевым моментом здесь является разница между тем, что такое «Бар», и тем, как вы используете его в том или ином контексте.
Бар - это единое целое в реальном мире (или искусственном мире, таком как игра), и только ОДИН экземпляр объекта должен представлять его. В любое время позже, когда вы не создадите этот экземпляр из сегмента кода, а загрузите его из файла конфигурации или базы данных, это станет более очевидным.
(Чтобы быть еще более эзотерическим: каждый экземпляр Bar имеет свой жизненный цикл, отличный от объекта, который представляет его при запуске вашей программы. Даже если у вас есть исходный код, который создает этот экземпляр, это означает, что сущность Bar, как она описана, "существует" "в состоянии покоя в исходном коде и" пробуждаться ", когда этот код фактически создает его в памяти ...)
Извините за долгое начало, но я надеюсь, что это проясняет мою точку зрения. У вас есть ОДИН класс Bar, имеющий все атрибуты, которые вам когда-либо понадобятся, и один экземпляр Bar, представляющий каждую сущность Bar. Это правильно в вашем коде и не зависит от того, как вы хотите видеть один и тот же экземпляр в разных контекстах .
Последний может быть представлен двумя различными интерфейсами , которые содержат необходимые методы доступа (getName (), getURL (), getDistance ()), и класс Bar должен реализовывать оба. (И, возможно, «расстояние» изменится на «местоположение», а getDistance () станет вычислением из другого места :-))
Но создание предназначено для сущности Bar, а не для того, как вы хотите использовать эту сущность: один конструктор, все поля.
Отредактировано: я могу написать код! :-)
источник
Соответствующий шаблон
То, что вы ищете, чаще всего называют
Null Object Pattern
. Если вам не нравится имя, вы можете называть егоUndefined Value Pattern
одинаковой семантикой, другой меткой. Иногда этот шаблон называетсяPoison Pill Pattern
.Во всех этих случаях Объект является заменой или заменой
Default Value
вместоnull. It doesn't replace the semantic of
нулевого значенияbut makes it easier to work with the data model in a more predictable way because
null`, теперь никогда не должно быть допустимым состоянием.Это шаблон, в котором вы резервируете специальный экземпляр данного класса для представления другой
null
опции какDefault Value
. Таким образом, вам не нужно проверятьnull
, вы можете проверить идентичность по вашему известномуNullObject
экземпляру. Вы можете безопасно вызывать методы и тому подобное, не беспокоясь о нихNullPointerExceptions
.Таким образом, вы заменяете свои
null
задания их представительнымиNullObject
экземплярами, и все готово.Правильный объектно-ориентированный анализ
Таким образом, вы можете иметь общее
Interface
для полиморфизма и при этом иметь защиту от необходимости беспокоиться об отсутствии данных в конкретных реализациях интерфейса. Таким образом, некоторыеBar
могут не иметь веб-присутствия, а некоторые могут не иметь данных о местоположении во время создания.Null Object Patter
позволяет установить значение по умолчанию для каждого из них , что являетсяmarker
для этих данных, говорит , что то же самое, ничего не было поставлено здесь, не имея дело с проверкой наNullPointerException
повсюду.Правильный объектно-ориентированный дизайн
Во- первых есть
abstract
реализация , которая является супер набором всех атрибутов, какBar
иClub
доли.Тогда можно реализовать вложенные классы этого
Establishment
класса и добавить только определенные вещи , которые нужны для каждого изBar
иClub
классов , которые не применяются к другим.Упорство
Эти объекты-заполнители, если они построены правильно, могут прозрачно храниться в базе данных без какой-либо специальной обработки.
На будущее
Если вы решили перейти к победе в Inversion of Control / Dependency Injection позже, этот шаблон также позволяет легко вводить эти маркерные объекты.
источник
Я думаю, проблема в том, что вы не моделируете Бар в любом из этих сценариев (и вы моделируете две разные проблемы, объекты и т. Д.). Если я увижу бар класса, я бы ожидал, что некоторые функции, связанные с напитками, меню, доступными местами, и ваш объект не имеют ничего подобного. Если я вижу поведение ваших объектов, вы моделируете информацию об учреждении. Бар - это то, для чего вы используете их в данный момент, но это не внутреннее поведение, которое они реализуют. (В другом контексте: если вы моделируете Брак, у вас будет две переменные экземпляра «Личность»; «Личность»; «Жена» - это текущая роль, которую вы отводите этому объекту в данный момент, но объект по-прежнему «Личность»). Я бы сделал что-то вроде этого:
источник
Там действительно нет необходимости слишком усложнять это. Вам нужны два разных типа объектов? Сделай два занятия.
Если вам нужно работать с ними одинаково, рассмотрите возможность добавления интерфейса или использования отражения.
источник
null
. Помнитьnull
означает отсутствие данных , а не отсутствие атрибута.Мой ответ всем, кто сталкивается с такой проблемой, - разбить ее на управляемые шаги .
BarOne
иBarTwo
(или назовите их оба,Bar
но в разных пакетах)bar
ли они оба, если не переименовать класс-нарушитель в то, что он теперь представляетinterface
илиsuperclass
с общим поведениемinterface
илиsuperclass
вы можете создатьbuilder
илиfactory
создать / получить ваши объекты реализации(4 и 5 - то, о чем другие ответы на этот вопрос)
источник
Вам нужен базовый класс, например, Location, который имеет имя и адрес . Теперь у вас есть два класса Bar и BarPreview, расширяющие базовый класс Location . В каждом классе вы инициализируете общие переменные суперкласса, а затем свои уникальные переменные:
И похоже на класс BarPreview ..
Если это заставляет вас спать лучше ночью, замените все экземпляры Location в моем коде на AnythingYouThinkWouldBeAnAppresponNameForAThingThatABarExtendsSuchAsFoodServicePlace - ffs.
источник
final
.final
в поля @David.Bar
не должно,extend Location
хотя это не имеет смысла. Возможно,Bar extends BaseBar
иBarPreview extends BaseBar
эти названия не очень хорошо звучат, хотя, я надеялся на что-то более элегантное