Я начинающий разработчик игр, я работаю над случайными инди-играми, и какое-то время я занимался чем-то, что поначалу казалось плохой практикой, но я действительно хочу получить ответ от некоторых опытных программистов здесь.
Допустим, у меня есть файл с именем, в enumList.h
котором я объявляю все перечисления, которые хочу использовать в своей игре:
// enumList.h
enum materials_t { WOOD, STONE, ETC };
enum entity_t { PLAYER, MONSTER };
enum map_t { 2D, 3D };
// and so on.
// Tile.h
#include "enumList.h"
#include <vector>
class tile
{
// stuff
};
Основная идея заключается в том, что я объявляю все перечисления в игре в 1 файле , а затем импортирую этот файл, когда мне нужно использовать определенное перечисление из него, а не объявляю его в файле, где мне нужно его использовать. Я делаю это, потому что это делает вещи чистыми, я могу получить доступ к каждому перечислению в 1 месте, а не открывать страницы исключительно для доступа к одному перечислению.
Это плохая практика и может ли она как-то повлиять на производительность?
источник
materials_t
файлы, которые не имеют отношения к материалам, их придется перестраивать.enumList.h
создавая коллекцию#include
s для этих файлов. Это позволяет файлам, которым требуется только одно перечисление, получить его напрямую, при этом предоставляя единый пакет для всего, что действительно требует их всех.Ответы:
Я действительно считаю, что это плохая практика. Когда мы измеряем качество кода, мы называем его гранулярностью. Ваша гранулярность сильно страдает, если поместить все эти перечисления в один файл, и, следовательно, ухудшается удобство сопровождения.
Я бы имел один файл на каждое перечисление, чтобы быстро найти его и сгруппировать с поведенческим кодом определенной функциональности (например, перечисление материалов в папке, где поведение материала и т. Д.);
Вы можете подумать, что это чисто, но на самом деле это не так. Он объединяет вещи, которые не связаны друг с другом по функциональности и модульности, и уменьшает модульность вашего приложения. В зависимости от размера вашей кодовой базы и от того, насколько модульным вы хотите, чтобы ваш код был структурирован, это может перерасти в более серьезную проблему и нечистый код / зависимости в других частях вашей системы. Однако, если вы просто пишете небольшую монолитную систему, это не обязательно применимо. Тем не менее, я бы не стал так делать даже для небольшой монолитной системы.
источник
Да, это плохая практика не из-за производительности, а из-за ремонтопригодности.
Это делает вещи «чистыми» только в ОКР «собирать похожие вещи вместе» способом. Но это на самом деле не полезный и хороший вид «чистоты».
Сущности кода должны быть сгруппированы, чтобы максимизировать связность и минимизировать связывание , что лучше всего достигается путем группировки их в значительной степени независимые функциональные модули. Группировка их по техническим критериям (например, объединение всех перечислений) дает противоположное - объединяет код, который не имеет абсолютно никакой функциональной взаимосвязи, и помещает перечисления, которые могут использоваться только в одном месте, в другой файл.
источник
Ну, это просто данные (а не поведение). Худшее, что могло бы / теоретически случиться, это то, что один и тот же код включен и скомпилирован более одного раза, создавая относительно большую программу.
Просто невозможно, чтобы такие включения могли добавить больше циклов к вашим операциям, учитывая, что внутри них нет никакого поведенческого / процедурного кода (без циклов, без if и т. Д.).
(Относительно) более крупная программа вряд ли может повлиять на производительность (скорость выполнения) и, в любом случае, является лишь теоретической проблемой. Большинство (может быть, все) компиляторы управляют включениями таким образом, чтобы предотвратить такие проблемы.
ИМХО, преимущества, которые вы получаете с одним файлом (более читаемый и более управляемый код), в значительной степени превосходят любые возможные недостатки.
источник
Для меня все зависит от масштаба вашего проекта. Если есть один файл, скажем, с 10 структурами, и это единственные из когда-либо использовавшихся файлов, мне было бы вполне удобно иметь для него один файл .h. Если у вас есть несколько разных типов функциональности, скажем, юниты, эконом, здания и т. Д., Я бы определенно разделил вещи. Создайте unit.h, где находятся все структуры, которые имеют дело с юнитами. Если вы хотите что-то сделать с блоками где-то, вам нужно обязательно включить unit.h, но это также хороший «идентификатор», что что-то с блоками, вероятно, сделано в этом файле.
Посмотрите на это так, вы не покупаете супермаркет, потому что вам нужна банка кока-колы;)
источник
Я не разработчик C ++, поэтому этот ответ будет более общим для OOA & D:
Как правило, объекты кода должны быть сгруппированы с точки зрения функциональной релевантности, а не с точки зрения языковых конструкций. Ключевой вопрос «да-нет», который всегда следует задавать: «Ожидается ли, что конечный кодер будет использовать большинство или все объекты, которые они получают при использовании библиотеки?» Если да, сгруппируйтесь. Если нет, рассмотрите возможность разделения объектов кода и размещения их ближе к другим объектам, которые в них нуждаются (тем самым увеличивая вероятность того, что потребителю потребуется все, к чему он фактически обращается).
Основная концепция - «высокая сплоченность»; члены кода (от методов класса до классов в пространстве имен или DLL и самих DLL) должны быть организованы так, чтобы кодер мог включать в себя все, что им нужно, и ничего, что они не делают. Это делает общий дизайн более терпимым к изменениям; вещи, которые должны измениться, могут быть без влияния на другие объекты кода, которые не должны были изменяться. Во многих случаях это также делает приложение более эффективным с точки зрения памяти; DLL полностью загружается в память, независимо от того, сколько из этих инструкций когда-либо выполнялось процессом. Поэтому для разработки «простых» приложений необходимо обращать внимание на объем кода, помещаемого в память.
Эта концепция применима практически на всех уровнях организации кода, с различной степенью влияния на удобство обслуживания, эффективность использования памяти, производительность, скорость сборки и т. Д. Если кодировщик должен ссылаться на заголовок / DLL довольно монолитного размера только для доступа к одному объекту, который не зависит ни от какого другого объекта в этой DLL, тогда включение этого объекта в DLL, вероятно, следует пересмотреть. Однако можно пойти и другим путем; DLL для каждого класса - плохая идея, потому что она замедляет скорость сборки (больше библиотек DLL для перестройки с соответствующими издержками) и делает версионирование кошмаром.
Показательный пример: если любое реальное использование вашей библиотеки кода будет связано с использованием большинства или всех перечислений, которые вы помещаете в этот единственный файл "enumerations.h", то непременно сгруппируйте их вместе; Вы будете знать, где искать их. Но если вашему кодирующему потребителю может понадобиться только один или два из десятков перечислений, которые вы предоставляете в заголовке, я бы посоветовал вам поместить их в отдельную библиотеку и сделать ее зависимой от более крупной библиотеки с остальными перечислениями. , Это позволяет вашим кодировщикам получать только один или два, которые они хотят, без связи с более монолитной DLL.
источник
Подобные вещи становятся проблемой, когда несколько разработчиков работают над одной и той же кодовой базой.
Я, конечно, видел, как похожие глобальные файлы становятся связующим звеном для коллизий слияния и всевозможных проблем в (более крупных) проектах.
Однако, если вы являетесь единственным, кто работает над проектом, тогда вы должны делать все, что вам больше всего удобно, и применять «лучшие практики», только если вы понимаете (и соглашаетесь с) мотивы, стоящие за ними.
Лучше сделать несколько ошибок и извлечь из них уроки, чем рискнуть застрять в практике программирования культовых грузов на всю оставшуюся жизнь.
источник
Да, это плохая практика для большого проекта. ПОЦЕЛУЙ.
Молодой сотрудник переименовал простую переменную в основной файл .h, и 100 инженеров ждали 45 минут, пока все их файлы не будут восстановлены, что повлияло на производительность каждого. ;)
Все проекты начинаются с малого, с годами, и мы проклинаем тех, кто раньше использовал короткие пути для создания технического долга. Лучшие практики, ограничивайте глобальный контент .h тем, что обязательно является глобальным.
источник
В этом случае, я бы сказал, что идеальный ответ заключается в том, что это зависит от того, как используются перечисления, но в большинстве случаев, вероятно, лучше определить все перечисления по отдельности, но если какой-либо из них уже связан по проекту, вы должны предоставить средство совместного введения упомянутых связанных перечислений. По сути, у вас уже есть допуск на связывание до количества преднамеренного связывания, но не более.
Учитывая это, наиболее гибкое решение, скорее всего, определит каждое перечисление в отдельном файле, но предоставит связанные пакеты, когда это целесообразно сделать (что определяется предполагаемым использованием задействованных перечислений).
Определение всех ваших перечислений в одном и том же файле объединяет их вместе, и, соответственно, любой код, который зависит от одного или нескольких перечислений, зависит от всех перечислений, независимо от того, использует ли код какие-либо другие перечисления.
renderMap()
Скорее всего, об этом знаютmap_t
, потому что в противном случае любые изменения в других будут влиять на него, даже если он на самом деле не взаимодействует с другими.Однако в случае, когда компоненты уже связаны друг с другом, предоставление нескольких перечислений в одном пакете может легко обеспечить дополнительную ясность и простоту, при условии, что есть очевидная логическая причина для объединения перечислений, что использование этих перечислений также связано, и что их предоставление также не вводит никаких дополнительных соединений.
В этом случае нет прямой логической связи между типом объекта и типом материала (при условии, что объекты не сделаны из одного из определенных материалов). Однако, если у нас был случай, когда, например, одно перечисление явно зависит от другого, то имеет смысл предоставить единый пакет, содержащий все связанные перечисления (а также любые другие связанные компоненты), так что связь может быть изолированы от этой упаковки настолько, насколько это возможно.
Но, увы ... даже когда два перечисления по своей сути связаны друг с другом, даже если это что-то столь же сильное, как «второе перечисление предоставляет подкатегории для первого перечисления», может все же наступить момент, когда необходимо только одно из перечислений.
Следовательно, поскольку мы знаем и то, что всегда могут быть ситуации, когда определение нескольких перечислений в одном файле может добавить ненужную связь, и что предоставление связанных перечислений в одном пакете может прояснить предполагаемое использование и позволить нам изолировать сам фактический код связи как Насколько это возможно, идеальным решением является определение каждого перечисления отдельно и предоставление совместных пакетов для любых перечислений, которые предназначены для частого использования вместе. Единственными перечислениями, определенными в одном и том же файле, будут те, которые неразрывно связаны друг с другом, так что использование одного также требует использования другого.
источник