2010-09-10 2 views
9

Где вы рисуете линию при перемещении функций, которые работают с данными в классе, который содержит эти данные? Например, представьте, что у вас есть простой класс, в котором хранится описание погоды с переменными температуры, влажности, скорости и направления ветра и временем, в которое было произведено измерение. Теперь представьте, что у вас есть объект этого класса, и вы хотите передать его кому-то другому - другому процессу, другой машине, что угодно. Вы помещаете код для передачи объекта в сам объект - например, путем добавления метода Send (тип назначения) к простому классу данных? Или вы сохраняете эту функцию в отдельных классах, которые могут отправлять и получать что-либо по всему средству - будь то сетевое взаимодействие, файловый ввод/вывод, межпроцессный обмен или что-то подобное?Объекты, которые отправляют себя - хорошая идея?

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

Это кажется мне очевидным, но я вижу, что разработчики применяют методы Send() на своих классах. Они даже сообщают сообщениям классам Отправить() сами, что кажется мне очень противоречивым; если я напишу письмо на листе бумаги, я не скажу, чтобы газета отправила себя. Я переношу письмо в конверт и передаю его почтальону, потому что у него есть фургон и карта. Что думают люди?

+0

Возможно, вас заинтересует вопрос: [Является ли хорошим соглашением для класса выполнять функции на себя?] (Http://stackoverflow.com/q/3105692/240733) – stakx

+0

Спасибо всем, кто ответил - это был моим первым вопросом о SO, и это был очень положительный опыт. – bythescruff

ответ

8

Существует логика, связанная с элементом полезной нагрузки: какова скорость ветра сейчас?

Существует логика делать это с интерпретацией этих данных: можем ли мы докровать этот корабль сейчас?

Есть логика, чтобы решить, куда отправить полезную нагрузку где-то: о, вот новое значение погоды, какая-то там забота.

После этого фактический материал сети.

Полезная нагрузка, вероятно, должна быть способна сериализовать и десериализовать себя. Я не вижу, чтобы какая-либо остальная часть интереса была полезной. Лучшее место для Send(). Не в последнюю очередь потому, что вы можете сразу отправить несколько объектов полезной нагрузки, и они не могут отправлять друг друга.

5

Несколько раз в моей карьере я неоднократно бывал в этом вопросе дизайна. Прямо сейчас, я нахожусь там, где вы, кажется, в основном потому, что я делаю много SOA в моей текущей жизни, и в итоге я пишу много кланов, которые существуют только для сериализации, проводных форматов, в основном связанных с XML и JSON.

Когда вы переходите в мир «услуг», классы часто представляют собой просто данные, которые отправляются туда и обратно. Поэтому я обобщаю свои классы на два логических ведра, «классы, содержащие данные» и «классы, которые делают вещи». Я не знаю, являюсь ли я единственным, кто делает такие вещи, но я здесь.

6

Это не простой вопрос. Я делал проекты с использованием обоих подходов, и в целом я был более счастливым, работая с подходом «умной модели», где модель многое знает о том, как делать вещи своими собственными данными.

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

Однако я не хочу, чтобы это привело к разрыву границ между слоями приложения. Я не хочу, чтобы бизнес-объект знал, как представлять себя как HTML - это проблема представления. Поэтому в этом случае я бы сказал, что класс должен знать, как представлять себя каноническим способом, но он не должен знать о сетевом материале. Фактическая функция отправки должна принадлежать службе.

+0

отличная статья! +1. – Armstrongest

+0

Когда вы говорите: «класс должен знать, как представлять себя каким-то каноническим способом», вы имеете в виду некоторые ДРУГИЕ канонические способы его свойств? – Mark

+0

@Mark - Я не уверен. Разумеется, класс может знать, как сериализовать себя в XML, например, но в реальном мире я часто обнаружил, что мне нужны несколько разные представления XML для разных ситуаций, и это больше похоже на проблему с презентацией. –

2

Короткий ответ - это зависит от того, с чем вы столкнетесь.

В целом, когда есть два способа сделать что-то, это обычно означает, что оба пути имеют свои достоинства. Примером может служить несколько примеров (SQL vs. NoSQL, Automatic vs Manual Transmission, Alternating vs Direct Current, Client Side vs Server Side и т. Д.). Результатом этого является то, что вы обязаны получать много людей с обеих сторон с мнениями, которые имеют заслуги.

Итак, вопрос, который вы поднимаете, - это когда объект может манипулировать собственными данными и когда мне нужно его разделить.

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

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

Например, если методы String, такие как Split, Join и Substring, нелегко найти в классе String и вместо этого, где где-то еще, например, гипотетический класс Parse, вероятно, до того, как я найду этот гипотетический класс Parse, я бы написал несколько дерьмовых версий этих методов. Реальный пример этого - когда люди пишут методы, идентичные методам в классе Math, потому что они не знают об этом.

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

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

Смежные вопросы