Должен ли объект представлять сущность?
Под организацией я имею в виду нечто вроде Product
, Motor
, А и ParkingLot
т.д., физическая, или даже четкий нефизических концептуального объекта - то , что хорошо определен, с некоторыми основными данными явно принадлежащими к объекту, а также некоторые функции / методы которые четко оперируют основными данными.
Например, у меня может быть объект Demon
, сущность сама по себе, воображаемая, может быть, и не физическая, а, тем не менее, сущность
Может ли объект быть просто набором методов , общим набором процедур, которые связаны с общей целью?
Пример: может быть вызван класс MotorOperations
или MotorActions
, где нет сущности, но методы внутри класса делают такие вещи, как
- getMotorDataFromHTMLForm ()
- getMotorManufacturers ()
- selectMotorFromUserRequirements ($ требования)
- canMotorCanHandleOperatingConditions ($ условие)
- computePowerConsumptionForMotor ($ ID)
Класс обычно определяется как данные, центральные для объекта + операции с данными. Таким образом, для a Motor
могут быть некоторые переменные двигателя, относящиеся к техническим характеристикам двигателя, и могут быть операции, которые объединяют эти данные для получения чего-либо.
В моем случае это больше похоже на то, что у меня есть класс с операциями над данными + данные, которые передаются через класс, нет никаких данных, ориентированных на «моторные операции», кроме временных данных сквозного прохождения класса.
Вопрос
Могут ли классы представлять объекты без сущности? Если нет, то почему они плохие / неполные / не ООП-ориентированные? Существуют ли способы их концептуального изменения / улучшения, чтобы они соответствовали ООП?
MotorActions
илиMotorOperations
хорошие идеи или нет.Ответы:
Нет , объект не должен представлять сущность.
На самом деле, я бы сказал, что когда вы перестаете думать об объектах как о физических объектах, это когда вы, наконец, получаете преимущества, которые обещает ООП.
Это не лучший пример, но дизайн кофеварки - это, вероятно, то место, где мне начали светиться.
Объекты о сообщениях. Они об обязанностях. Они не об автомобилях, пользователях или заказах.
Я знаю, что мы преподаем ОО таким образом, но после нескольких попыток становится очевидным, насколько фундаментально сложно расставаться, когда дела идут, когда вы пытаетесь сделать MVC, MVVM или MVW, что угодно. Либо ваши модели становятся смехотворно раздутыми, либо контроллеры. Для удобства навигации важно знать, что все, что касается транспортных средств, находится в файле Vehicle.ext, но когда ваше приложение относится к транспортным средствам, вы неизбежно получите 3000 строк спагетти в этом файле.
Если у вас есть новое сообщение для отправки, у вас есть как минимум один новый объект и, возможно, пара из них. Так что в вашем вопросе о пакете методов я бы сказал, что вы потенциально говорите о пакете сообщений. И каждый из них может быть своим собственным объектом, со своей работой. И это нормально. Это станет очевидным, когда вы разделите вещи на части, которые действительно должны быть вместе. И ты собрал их вместе. Но вы не сразу бросаете каждый метод в смутно подходящий ящик для удобства, если хотите насладиться ОО.
Давайте поговорим о мешках функций
Объект может быть просто набором методов и при этом быть ОО, но мои «правила» довольно строги.
На коллекцию должна быть возложена одна ответственность, и эта ответственность не может быть такой же общей, как «Делает вещи для моторов». Я мог бы сделать такую вещь, как фасад уровня сервиса, но я прекрасно осознаю, что мне лень по причинам навигации / обнаружения, а не потому, что я пытаюсь написать ОО-код.
Все методы должны быть на согласованном уровне абстракции. Если один метод извлекает объекты Motor, а другой возвращает мощность, это, вероятно, слишком далеко друг от друга.
Объект должен работать на тех же «видах» данных. Этот объект работает с двигателями (запуск / останов), этот работает с длинами кривошипа, этот обрабатывает последовательность зажигания, этот принимает форму HTML. Эти данные могут быть полями на объекте, и они могут показаться связными.
Обычно я создаю объекты такого рода, когда я выполняю преобразования, компоновку или просто не хочу беспокоиться об изменчивости.
Я считаю, что сосредоточение на предметных обязанностях ведет меня к сплоченности. Чтобы быть объектом, должна быть некоторая сплоченность, но для того, чтобы он был объектом, не требуется никаких полей или поведения. Если бы я строил систему, которая нуждалась в этих 5 моторных методах, я бы начал с 5 разных объектов, которые делают эти вещи. Когда я нашел общность, я бы либо начал объединять вещи, либо использовал общие «вспомогательные» объекты. Это приводит меня к открытым / закрытым проблемам - как я могу извлечь эту часть функциональности, чтобы мне больше никогда не приходилось изменять этот конкретный файл, а использовать его там, где это необходимо?
Объекты о сообщениях
Поля почти не имеют значения для объекта - получение и установка регистров не изменяет мир вне программы. Сотрудничество с другими объектами делает работу. Однако сила OO в том, что мы можем создавать абстракции, поэтому нам не нужно думать обо всех отдельных деталях одновременно. Абстракции, которые утекли или не имеют смысла, проблематичны, поэтому мы глубоко (слишком много, может быть) думаем о создании объектов, которые соответствуют нашим ментальным моделям.
Ключевой вопрос: почему эти два объекта должны общаться друг с другом?
Думайте об объекте как об органе в человеке - он имеет цель по умолчанию и меняет поведение только тогда, когда получает определенное сообщение, которое ему небезразлично.
Представьте себе сценарий, когда вы находитесь на пешеходном переходе, и машина едет быстро. Как объект мозга, я обнаруживаю стрессор. Я говорю гипоталамусу отправлять кортикотрофин-рилизинг-гормон. Гипофиз получает это сообщение и выпускает кортикотрофный гормон надпочечников. Надпочечники получают это сообщение и создают адреналин. Когда мышечный объект получает это сообщение адреналина, он сжимается. Когда сердце получает то же сообщение, оно бьется быстрее. Есть целая цепь игроков, вовлеченных в запуск сложного поведения бега через улицу, и это сообщения, которые имеют значение. Объект мозга знает, как заставить гипоталамус отправлять оповещение, но он не знает цепочку объектов, которые в конечном итоге приведут к тому, что поведение будет происходить. Точно так же сердце не знает, откуда берется адреналин,
Таким образом, в этом ( упрощенном ) примере объект надпочечников должен знать, как принимать АКТГ и вырабатывать адреналин. Для этого не нужны никакие поля, но мне все еще кажется, что это объект.
Теперь, если наше приложение предназначено только для бега через улицу, мне могут не понадобиться объекты гипофиза и надпочечников. Или мне нужен только объект гипофиза, который выполняет лишь небольшую часть того, что мы можем концептуально рассматривать как «модель гипофиза». Все эти понятия существуют как концептуальные сущности, но это программное обеспечение, и мы можем создать AdrenalineSender или MuscleContractor или что-то еще и не беспокоиться о «неполноте» нашей модели.
источник
MotorOperations
илиMotorActions
". Исходя из этого, я вполне уверен, что как исходный, так и окончательный дизайн классов из примера CoffeeMaker подпадают под определение ОП «представлять сущность»Короче говоря, вы можете делать что угодно, но этот конкретный сценарий противоречит принципам ООП :)
То, что вы описываете, иногда называют «служебным» классом - обычно признаком запаха кода. Вы хотите избегать создания классов, чтобы сохранить некоторые методы вместе.
Не каждый объект в вашем приложении должен быть связан с реальной сущностью, такой как двигатель или автомобиль; это бизнес-объекты. В вашем приложении вы, вероятно, будете использовать многие из своих бизнес-объектов, но вам также потребуется дополнительная сегрегация для других операций, которые не являются частью бизнес-объектов, таких как перечисленные вами.
Вы должны взглянуть на общие архитектурные шаблоны - один из них - MVC (Model-View-Controller) .
Если бы я распространял методы, которые вы перечислили, используя MVC, я бы сделал следующее:
Посмотреть класс:
Класс модели (мотор по существу):
Класс контроллера (MotorsController):
Похоже, вы используете PHP; хорошая структура MVC, чтобы взглянуть на это Laravel . В своих примерах они хорошо иллюстрируют, к каким методам относятся.
Другим, более общим источником информации о том, как определить, к каким методам относятся, являются принципы GRASP и SOLID .
источник
MotorOperations
вMotorsController
и очистить его немного, мой набор функций будет осуществляться в соответствии с ООП?Utils
класс является примером запаха кода? Просто любопытно, так как мне самому нравилось иметь вUtils
классе случайные функции утилит, а не просто быть автономными функциями ... по моему опыту это делает код немного более читабельным, но мой опыт ограничен.Можно? Да. Должен? Наверное, нет - или, по крайней мере, не так, как вы формулируете вещи.
Объекты на самом деле лучше, когда они не представляют физический объект напрямую, поскольку реальность так редко отображается в коде. Но они действительно должны представлять связную концепцию или объект кода. Они должны представлять единую ответственность.
Простое связывание связки тангенциально связанных функций - это пространство имен или модуль, а не объект на языке ООП. Они могут быть полезны, но они не одинаковы, и для их эффективной работы требуется другой тип использования / мышления.
источник
bundling a bunch of tangentially related functions together is a namespace
это больше похоже на процедурную парадигму, чем на объектно-ориентированную.Класс должен что-то моделировать - иначе это бессмысленно. Однако то, что моделируется, не может быть физической «вещью»; вместо этого это может быть представление чего-то, что не является «реальным», но что необходимо для управления моделируемой системой. Например, в системе управления светофорами вы вполне могли бы иметь некоторый класс ControlSignal, представляющий сигнал, отправляемый из одной части системы в другую, чтобы указать, что необходимо выполнить какое-то действие. В «реальном мире» эти сигналы могут состоять из электрических импульсов, передаваемых по проводам от одного блока к другому. Процесс моделирования чего-то, что не является «реальным» в качестве конкретного объекта, называется «овеществлением».
Удачи.
источник
Нет. (Название отредактировано, чтобы задать противоположный вопрос!)
например:
или же
Однако в целом идеал, стоящий за ООП, - это отойти от
в
источник
Я думаю, что визуализация чего-либо в реальном мире полезна при кодировании классов, но не обязательна.
Фактически, в зависимости от того, насколько буквальным вы хотите быть, многие объекты, с которыми мы работаем, вообще не имеют физических представлений. Например, рассмотрим архитектуру MVC. В реальном мире нет моделей или контроллеров, даже если они обычно представлены классами. Три вместе часто представляют что-то, но не всегда - но, как я уже сказал, вы, вероятно, можете заставить что-то вписаться во что-то, если вы действительно этого хотите (и возможность представить, что ЧТО-ТО помогает! Вы бы когда-нибудь увидели в реальном мире).
В основном эти «правила», которые вы узнаете об ОО, представляют собой всего лишь руководящие принципы, призванные помочь вам ориентироваться в ОО, а не в том, о чем вы часто беспокоитесь, когда используете его для ежедневного программирования.
Между прочим, сам по себе ОО не является панацеей, и он совсем не поможет вам во время вашего первого прохода при написании какого-либо решения, но я думаю, что если все сделано правильно, это действительно фантастический способ организовать код, чтобы он мог быть более легко понять позже. Написание поддерживаемого кода, вероятно, является одной из самых сложных задач в разработке программного обеспечения, и во многих случаях (все, что требует постоянной отладки / обслуживания), безусловно, является наиболее важной.
источник
Вопрос: Какую сущность
Logger
представляет?Не в переносном смысле - в буквальном смысле.
При объяснении ООП студентам полезно объяснять объекты с аналогиями с физическим миром.
Алан Кей - один из отцов ООП - написал следующее:
источник
Исходя из этого, объекты лучше всего понимать как
автаркические объекты, инкапсулирующие / скрывающие данные
общение с другими объектами с помощью сообщений
Определенно: подумайте о
Math
По поводу вашего примера:
Чтобы решить, куда поместить эти методы, вы должны взглянуть на
responsibilities
: кто за что отвечает .Контекстом такого метода будет конструирование моторного объекта . Мотор не несет ответственности за создание себя из данных, полученных с помощью формы . Есть как минимум два объекта; один - двигатель, а другой - создатель двигателя .
Типичный контекст, в котором можно написать такой метод, это
service
.Это также будет использоваться в
service
-contextЭто вопрос к
motor
-объектуЭто тоже вопрос, который лучше всего задать самому двигателю.
ТЛ; др
Метафора
objects
как физически объектов более раздражающего , чем полезно.источник
thing
с данными, когда данные явно принадлежат вещи, и функции, которые явно работают с данными, принадлежащими этой вещи». Таким образом, Logger в данном случае, хотя и не физическая вещь, это понятие, похожее на «физическую книгу журналов». Имеются ли у него данные, которые являются ключевыми для его состояния, а не просто кратковременны для него, это может зависеть от реализации и интерпретации ... и в большей степени от того, куда уходит мой вопрос ..Да, ты можешь это сделать. Но вы, по сути, создаете класс, обеспечивающий ту же функциональность, что и процедурная библиотека. Единственная причина сделать это, если в вашем языке отсутствуют процедурные модули (например, Java или Ruby).
На языке с процедурными модулями (я думаю, что в PHP есть процедурные модули), вы можете рассмотреть возможность использования только процедурного модуля.
Вы также можете подумать о перепроектировании своего класса, чтобы экземпляр класса представлял собой целостный объект.
Но используйте обозначение OO только тогда, когда оно дает вам дополнительную мощность, а не только ради того, чтобы быть OO!
источник
По словам непрофессионала
Такие классы существуют, например, Java SDK имеет класс Collections, который состоит исключительно из статических методов, которые работают или возвращают коллекции.
Таким образом, ответ будет «нет», не все классы должны моделироваться из сущности домена.
С другой стороны, в программе, написанной на языке ООП, таких классов мало или их должно быть всего несколько, поскольку реальная сила ООП заключается в полиморфизме и инкапсуляции.
Это все равно что использовать самолет, чтобы лететь из одного места в другое, не летая, а проезжая по автострадам. У самолетов есть колеса, как у автомобилей, но они предназначены для полета.
источник
Нет, класс просто представляет то, что может быть создано, имеет членов и может быть унаследовано.
Фактически, ваш язык может иметь статические классы, которые даже не создаются более одного раза.
.NET
Math
- отличный пример «профессионального» класса, который не представляет никакой сущности (если только вы не хотите философствовать о том, что такое математика ...), а также иллюстрирует законный вариант использования такого класса. Он имеет только методы и 2 поля (оба представляют отдельные константы).Иерархия классов подобной библиотеки
Math.Net
группирует математические / численные методы по классам по типу. Здесь классы представляют не сущность, а логическую категорию.Я сам часто заканчиваю тем, что создаю (статические) классы, которые представляют собой не что иное, как пакет связанных (статических) функций или набор констант, удобно сгруппированных в одном центральном месте. Я бы не сказал, что это хороший дизайн, но иногда это самое простое решение.
источник
Ответы на ваши вопросы в конечном счете зависят от того, насколько точно определены такие термины, как «класс» и «сущность». Вы проделали хорошую работу по определению последнего, допуская как физические, так и концептуальные сущности. Но термин «класс» для пуристов всегда будет «фабрикой для создания экземпляров объектов с определенным внутренним представлением», а для прагматиков этот термин будет охватывать те вещи Java или C ++, которые презирают пуристы. То же самое относится к термину «ООП», который прагматики могли бы сказать, что Java и C ++ делают, но который пуристы будут понимать, что имел в виду Алан Кей, когда он заметил [«Я изобрел термин объектно-ориентированный, и я могу сказать, что я этого не делал» иметь в виду C ++ "] ( Так что же на самом деле имел в виду Алан Кей под термином" объектно-ориентированный "? ).
Если вы придерживаетесь прагматического взгляда, вы можете принять ваши вспомогательные классы без экземпляра. Но пуристская точка зрения более интересна. По словам Кея, ООП всегда было больше связано с сообщениями, чем с классами. Итак, на ваши вопросы:
Нет. Классы классифицируют объекты. Классы по определению являются теми объектами, которым вы отправляете сообщение, например,
new
для создания объекта. Объект - это сущность, созданная из класса. Существуют классы для производства и классификации объектов. Это то, что делают классы. Классы делают объекты. Мы используем классы для классификации объектов. Так что, если C - это просто набор методов, которые не позволяют создавать экземпляры или создавать подклассы, не может быть никаких объектов, классифицированных по C, поэтому C не является классом.Они не плохие. Только не называй их классами. Пакет методов является OOPable: что-то, на что вы могли бы послать сообщение, чтобы вызвать метод, но это не класс, если он не может создать экземпляр объекта. Ты знаешь Руби? В Ruby модуль представляет собой набор методов. Класс представляет собой модуль , который может создавать объекты. В модуле нет ничего плохого . Но вещь, которая отличает класс от модуля (в чистом виде ООП), состоит в том, что у класса могут быть экземпляры. Модуль - это всего лишь несколько методов. Путаница заключается в том, что C ++, Java и другие языки используют термин «класс» как для класса, так и для модуля .
Теперь, чтобы взглянуть на один из ваших конкретных примеров, вы спрашиваете о
MotorOperations
классе, которому вы можете отправить сообщениеcomputePowerConsumptionForMotor
с аргументомid
. Это плохо? По крайней мере, это не нарушает принцип «Не спрашивай» . У нас есть сделать класс двигателя и послать емуpowerConsumption
сообщение? Возможно, не в 100% случаев, но, возможно, попытка сделать это приведет к хорошему пониманию вашего кода. Или это может привести к взрыву маленьких классов, что было бы плохо.Если «выполнение ООП» важно для вас, то вам нужно будет искать способы структурирования системы в компоненты, которые взаимодействуют путем отправки сообщений друг другу. То есть именно то , что ООП является или , по крайней мере , что монетоприемник термина имел в виду. С этой точки зрения служебные классы не являются ООП. Но для некоторых людей они могут быть.
Попытка создать целую большую систему из миллионов живых, дышащих объектов, созданных на основе классов, может работать для некоторых проектов. Но если вы обнаружите, что создаете искусственные, неправильно звучащие классы, тогда модули должны быть введены. Старайтесь делать акцент на классах и использовать модули, когда создаваемые экземпляры классов были бы смешными.
TL; DR - метод связок не всегда плох. Попробуйте сначала использовать инстанцируемые классы. Вернитесь к «модулям» только при необходимости.
источник
Принимая приведенные примеры:
Они похожи на «фабричные» методы, которые возвращают
Motor
объект. Второй подразумевает, что либо вы создаете новый объект для удовлетворения требований, либо у вас есть база данных или коллекция двигателей, которые вы изучаете в памяти. В этом случае это должен быть метод на этом. Или это может быть метод на объекте требований.Откуда ты их берешь? Вот к чему это должен быть метод.
Похоже, они должны быть методами
Motor
.источник
getMotorManufacturers
вернуть все производители двигателей из базы данных. Я не уверен, куда это идет. Мне понадобится некоторое время, чтобы разгадать этот BOPUM, чтобы положить вещи туда, куда им нужно идти ..getMotorManufacturers
из базы данных. В базе данных не может быть метода ... В настоящее время у меня есть шаблон DataMapper, который запрашивает базу данных, инициализирует массив и заполняет его объектами Motor (также содержащими информацию о производителе), а затем возвращает этот массив вызывающей стороне. Вызывающая сторона - это мойMotorOperations
класс, который, в свою очередь, вызывается изProductSelection
класса (который содержит алгоритм, который используется для выбора двигателей, а загруженная информация о двигателях - это данные для этого алгоритма)Объект представляет собой набор методов и данных, которые имеют высокую степень сцепления. Они принадлежат к классу, потому что они сильно взаимосвязаны и состояние сохраняется.
Это верно, независимо от того, используете ли вы большой предварительный дизайн и пытаетесь смоделировать все, или новый дизайн, когда вы повторяете и развиваете объект в соответствии с требованиями системы в данный момент.
Если у вас нет причин сохранять состояние, у вас, вероятно, нет причин создавать экземпляр объекта, что означает, что, вероятно, нет причин иметь класс. Если только язык, который вы используете, не имеет возможности определять пространство имен, кроме использования класса. В котором использование класса должно быть хорошо, потому что это было бы идиоматическим.
Я не могу думать ни о каких отрицательных аспектах использования классов таким способом, кроме типичного. Ваше приглашение лишних затрат и сложности требует создания «пространства имен». Любой, кто поддерживает этот код, задается вопросом, где данные стоят дополнительной когнитивной нагрузки (скорее всего, единовременные затраты на человека). Это необычное использование без какой-либо дополнительной ценности.
источник