Я пишу программу, которая включает в себя работу с полярными и декартовыми координатами.
Имеет ли смысл создавать две разные структуры для каждого вида точек, одна с X
и Y
членами, а другая с R
и Theta
членами.
Или это слишком много, и лучше иметь только одну структуру с членами first
и в second
качестве членов.
То, что я пишу, просто и не сильно изменится. Но мне любопытно, что лучше с точки зрения дизайна.
Я думаю, что первый вариант лучше. Это кажется более читабельным, и я получу преимущество проверки типов.
Ответы:
Я видел оба решения, поэтому оно определенно зависит от контекста.
Для удобства чтения наличие нескольких структур, как вы предлагаете, очень эффективно. Однако в некоторых средах вы хотите выполнить общие манипуляции с этими структурами, и вы обнаружите, что дублируете код, такой как матричные * векторные операции. Это может расстраивать, когда конкретная операция недоступна в вашем виде вектора, потому что никто не перенес ее туда.
Чрезвычайное решение (которое мы в конечном итоге дали) состоит в том, чтобы иметь шаблонный базовый класс CRTP с функциями get <0> () get <1> () и get <2> () для получения элементов в общем виде. Эти функции затем определяются в декартовой или полярной структуре, которая является производной от этого базового класса. Это решает все проблемы, но приходит по довольно глупой цене: нужно изучать метапрограммирование шаблонов. Однако, если шаблонное метапрограммирование уже является честной игрой для вашего проекта, это может быть хорошим совпадением.
источник
Да, это имеет большой смысл.
Значение структуры заключается не только в том, что она инкапсулирует данные под удобным именем. Значение состоит в том, что он кодифицирует ваши намерения, так что компилятор может помочь вам убедиться, что вы не нарушаете их когда-нибудь (например, ошибочный набор полярных координат для набора декартовых координат).
Люди плохо запоминают такие мелкие детали, но умеют создавать смелые, изобретательные планы. Компьютеры хорошо разбираются в деталях и плохо в творческих планах. Поэтому всегда полезно перенести на компьютер как можно больше мелких деталей, оставляя ваш ум свободным для работы над грандиозным планом.
источник
Да, хотя и декартовы, и полярные являются (на их месте) чрезвычайно разумными схемами представления координат, в идеале они никогда не должны смешиваться (если у вас есть точка декартова {1,1}, это очень отличная точка от полярной {1,1). }).
В зависимости от ваших потребностей, она также может быть стоит реализации координатно - интерфейс, с помощью методов , таких как
X()
,Y()
,Displacement()
иAngle()
(или , возможно ,Radius()
иTheta()
, в зависимости от).источник
В конце цель программирования состоит в том, чтобы переключить биты транзистора, чтобы сделать полезную работу. Но мышление на таком низком уровне приведет к неуправляемому сумасшествию, поэтому существуют языки программирования более высокого уровня, которые помогут вам скрыть сложность.
Если вы просто создаете одну структуру с именами членов
first
иsecond
, то имена ничего не значат; вы бы по существу относились к ним как к адресам памяти. Это противоречит цели языка программирования высокого уровня.Кроме того, только потому, что все они представимы как
double
не означает, что вы можете использовать их взаимозаменяемо. Например, θ - безразмерный угол, а у - единицы длины. Поскольку типы не являются логически заменяемыми, они должны быть двумя несовместимыми структурами.Если вам действительно нужно разыграть трюки с повторным использованием памяти - а вам почти наверняка это не нужно - вы можете использовать
union
тип в C, чтобы прояснить свое намерение.источник
Во-первых, имейте оба явно, согласно полностью обоснованному ответу @ Kilian-foth.
Тем не менее, я хотел бы добавить:
Спросите: действительно ли у вас есть операции, которые являются общими для обоих, если рассматривать их как пары
double
? Обратите внимание, это не то же самое, что сказать, что у вас есть операции, которые применяются к обоим в их собственных терминах. Например, «plot (Coord)» заботится о том,Coord
является ли полярным или декартовым. С другой стороны, сохранение файла просто обрабатывает данные как есть. Если у вас действительно есть общие операции, рассматривает как определение базового класса, или определения преобразователя кstd::pair<double, double>
илиtuple
или что - то у вас есть на вашем языке.Кроме того, один из подходов может заключаться в том, чтобы рассматривать один тип координат как более фундаментальный, а другой - просто как поддержку пользовательского или внешнего взаимодействия.
Таким образом, вы можете убедиться, что все основные операции закодированы,
Cartesian
а затем обеспечить поддержку для преобразованияPolar
вCartesian
. Это позволяет избежать реализации разных версий многих операций.источник
Возможное решение, в зависимости от языка и, если вы знаете, что оба класса будут иметь одинаковые методы и операции, состояло бы в том, чтобы определить класс один раз и использовать псевдонимы типов для явного именования типов по-разному.
Это также имеет то преимущество, что до тех пор, пока классы абсолютно одинаковы, вы можете поддерживать только один, но как только вам нужно их изменить, вам не нужно изменять код, используя их, так как типы уже использовались distincly.
Другой вариант, опять же зависящий от использования классов (если вам нужен полиморфизм и тому подобное), - это использовать открытое наследование для обоих новых типов, чтобы у них был тот же открытый интерфейс, что и у общего типа, который они оба представляют. Это также учитывает отдельную эволюцию типов.
источник
Я считаю, что иметь одинаковые имена членов в этом случае - плохая идея, потому что это делает код более подверженным ошибкам.
Представьте себе сценарий: у вас есть пара декартовых точек: pntA и pntB. Затем вы решаете, по какой-то причине, что они должны быть лучше представлены в полярных координатах, и меняете объявление и конструктор.
Теперь, если все ваши операции были просто вызовами методов, такими как:
тогда ты в порядке. Но что, если вы использовали членов явно? сравнить
В первом случае код не будет компилироваться. Вы сразу увидите ошибку и сможете ее исправить. Но если у вас одинаковые имена членов, ошибка будет только на логическом уровне, гораздо сложнее обнаружить.
Если вы пишете необъектно-ориентированным языком, тогда еще проще передать неправильную структуру в функцию. Что мешает вам написать следующий код?
С другой стороны, различные типы данных позволят вам найти ошибку во время компиляции.
источник