2015-03-24 4 views
4

Я новичок в C++, и я создаю игру. У меня есть класс, называемый основным, в котором я объявляюIs Extern Break Encapsulation

Game * game; //globally 
int main() { 
    game = new Game(); 
    game->show(); 
} 

Мой класс игра начинает свою игру и т.д. В настоящее время в других классах (игрок, враг и т.д.), я получить доступ к переменным из игры, такие как здоровье игрока, используя

#include<game.h> 
extern Game * game; 
func::func() { 
    game->health->resetHealth(); 
} 

Является ли эта парадигма инкапсуляции/ood нарушением? Это плохая практика? Дело в том, что я вижу другой способ сделать это для игры.

+1

В примере, который вы указали, вы можете легко использовать параметр. – chris

+0

Почему бы вам не сделать игру локальной переменной в главном? –

ответ

1

Да extern Прерывания инкапсуляции. Основная концепция инкапсуляции - свойство скрытия и привязки данных и поведение объекта в одном объекте. Изменение переменной extern нарушит закон.
В некоторых более продвинутых OOP язык как java нет extern. И в Java всегда предлагалось сделать свойство/поле частным, чтобы ограничить его доступ.

1

Я имею в виду, да, это не инкапсулировано. game - глобальный указатель, к которому можно получить доступ и изменить его из любого места. Инкапсуляция касается скрытия данных, и game полностью открыт. Это также не типичный объектно-ориентированный дизайн. Для правильной инкапсуляции и OOD вы должны ограничить, кто использует и «знает о» Game * game. Например, вы можете иметь объект GameController, который состоит из Game *. Объем и продолжительность жизни Game * могут жить в GameController, а затем GameController могут инкапсулировать его переменную-член, сделав ее частной и решить, кто, как и когда обращается к указателю. Существуют и другие подходы, такие как перенос указателя в глобальный одноэлементный класс. Это лучше, чем ваш пример, потому что класс wrapping может обеспечить соблюдение определенных инвариантов (например, что должно произойти при доступе к игре или о том, как клиент должен удалить игру). Как правило, глобальные синглтоны - это не лучший подход по причинам, выходящим за рамки этого ответа. Другой подход заключается в использовании инъекции зависимостей. Таким образом, всякий раз, когда класс должен модифицировать Game *, он будет иметь указатель, переданный в него. Это все объектно-ориентированные методы доступа к инкапсулированным данным.

+0

Синглтон - это еще один глобальный. Не стоит упоминать об этом. –

+0

Привет, спасибо за ответ. Можете ли вы объяснить мне немного лучше, как я буду использовать gameController или использовать инъекцию зависимостей. Смотрите, я делаю игру, в которой я ее запускаю, и все, кроме Im, используя много таймеров, и я не могу обмотать голову, делая это по-другому. Я исхожу из java-фона и использую qt для его создания. Я просто не хочу, чтобы это работало. Я хочу, чтобы это было, если вы знаете, что я имею в виду @JosephMalike. EDIT Также сама игра не имеет никаких атрибутов, которые она только создает мои окна и т. Д. –

+0

Это довольно большая тема. Там есть много отличных ресурсов для разработки. Возможно, вы могли бы размещать сообщения в программе Stack Exchange Programmers или Stack Exchange Code Review. Сделайте некоторые поисковые запросы Google для «инъекции зависимостей», «объектно-ориентированной компоновки дизайна» и «объектно-ориентированных шаблонов проектирования». Удачи! –

1

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

0

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

Вы можете подумать о том, что в вашей программе есть последовательность инициализации, называемая корнем композиции (для простых примеров главное - это наиболее очевидное место для этого), где вы передаете все зависимости, подобные этому, к объектам, которые им нужны, через конструктор, который называется инъекцией зависимостей.

Если вы хотите сделать еще один шаг, вы можете создать базовые классы и передать абстрактные базовые классы вместо объектов реализации. Таким образом, вы больше программируете на интерфейсы вместо объектов.

1

Использование самой глобальной переменной не нарушает инкапсуляцию - объект может скрыть детали реализации, насколько это было бы возможно, если бы оно не было глобальным. В большинстве случаев, однако, он противоречит другому принципу дизайна: гибкость. Скажем, вы хотите, чтобы ваша программа обрабатывала более одной игры за раз (если такое последующее изменение вообще не имеет смысла, вы можете решить сохранить его в глобальном масштабе).

Всякий раз, когда вы собираетесь объявить некоторую глобальную переменную, это, возможно, хорошо спросить себя:

  • было бы трудно избежать? (В показанном случае было бы легко просто передать объект game вокруг функций, которые в нем нуждаются.)
  • Возможно ли, что в более поздний момент времени будет не только один вид такого объекта? (Например, вы можете написать редактор для уровней игры, где вы хотите повторно использовать часть кода, и этот редактор должен иметь возможность редактировать несколько игр на нескольких вкладках.)
  • Использует ли глобальное упрочнение чтение кода? (Помните, что легко читать, это гораздо важнее, чем просто написать!)

В большинстве случаев лучше избегать глобальных переменных, на мой взгляд; и я думаю, что лучше избегать этого для случая, показанного в вопросе. Параметр A game может легко передаваться.

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