简体   繁体   English

Extern 是否打破封装

[英]Does Extern Break Encapsulation

I am new to C++ and I am creating a game.我是 C++ 的新手,我正在创建一个游戏。 I have a class called main in which I declare我有一个名为 main 的类,我在其中声明

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

My class game initiates my game etc. Now in other classes (player, enemy, etc.), I access variables from the game such as player health using我的班级游戏启动我的游戏等。现在在其他班级(玩家、敌人等)中,我从游戏中访问变量,例如玩家健康使用

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

Is this breaking encapsulation/ood paradigm?这是打破封装/ood 范式吗? Is it bad practice?这是不好的做法吗? The thing is I can see any other way of doing it for a game.问题是我可以看到任何其他的游戏方式。

Yes, extern breaks encapsulation.是的, extern打破了封装。 The main concept of encapsulation is data hiding and binding property and behavior of an object in a single entity.封装的主要概念是将数据隐藏和绑定在单个实体中的对象的属性和行为。 Making the variable extern would break the law.使变量extern会违反法律。
In some more advance OOP language like java , there is no extern .在一些更高级的OOP语言(如java ,没有extern And in Java, it always suggested making property/field private to restrict its access.在 Java 中,它总是建议将属性/字段设为私有以限制其访问。

I mean, yeah, it's not encapsulated.我的意思是,是的,它没有封装。 game is a global pointer that can be accessed and changed from anywhere. game是一个全局指针,可以从任何地方访问和更改。 Encapsulation is about data hiding, and game is totally exposed.封装就是数据隐藏, game完全暴露。 It is also not typical object-oriented design.它也不是典型的面向对象设计。 For proper encapsulation and OOD, you should restrict who uses and "knows about" the Game * game .为了正确封装和 OOD,您应该限制谁使用和“了解” Game * game For example, you can have a GameController object that is composed of a Game * .例如,您可以拥有一个由Game *组成的GameController对象。 The scope and lifetime of the Game * could live in GameController , and then GameController can encapsulate its member variable by making it private and deciding who, how and when the pointer is accessed. Game *的范围和生命周期可以存在于GameController ,然后GameController可以通过将其GameController私有并决定访问指针的人、方式和GameController来封装其成员变量。 There are other approaches, like wrapping the pointer in a global singleton class.还有其他方法,例如将指针包装在全局单例类中。 This is better than your example because the wrapping class can enforce certain invariants (like what should happen when the game is accessed, or how a client should delete a game).这比您的示例要好,因为包装类可以强制执行某些不变量(例如访问游戏时应该发生什么,或者客户端应该如何删除游戏)。 Typically, global singletons are not the best approach for reasons outside of the scope of this answer.通常,由于本答案范围之外的原因,全局单例不是最佳方法。 Another approach would be to use dependency injection.另一种方法是使用依赖注入。 So, whenever a class needs to modify the Game * , it would have the pointer passed into it.因此,每当一个类需要修改Game * ,它都会将指针传递给它。 These are all objected-oriented techniques for accessing encapsulated data.这些都是用于访问封装数据的面向对象技术。

Just having a global variable already starts breaking down your encapsulation because it provides access to the object from any code in your program.仅仅拥有一个全局变量就已经开始破坏您的封装,因为它提供了从程序中的任何代码访问对象的权限。 When you have a global like that any function can generate game-altering side effects, even ones in completely unrelated object instances.当你有一个这样的全局变量时,任何函数都可以产生改变游戏的副作用,即使是在完全不相关的对象实例中也是如此。 Using extern doesn't break encapsulation any further because it's roughly equivalent to just pasting more code into the single source file that declared the global.使用 extern 不会进一步破坏封装,因为它大致相当于将更多代码粘贴到声明全局的单个源文件中。

Using a global variable itself doesn't break encapsulation -- the object could hide its implementation details as much as it could if it were not global.使用全局变量本身不会破坏封装——如果对象不是全局变量,它可以尽可能多地隐藏其实现细节。 In most cases, it does, however, conflict with another design principle: flexibility.然而,在大多数情况下,它确实与另一个设计原则相冲突:灵活性。 Say, you want your program to handle more than one game at a time (if such a later change doesn't make sense at all, you may decide to keep it global).比如说,您希望您的程序一次处理多个游戏(如果这样的后期更改根本没有意义,您可以决定保持全局)。

Whenever you're about to declare some global variable, it's perhaps good to ask yourself:每当您要声明某个全局变量时,不妨问问自己:

  • Would it be hard to avoid it?很难避免吗? (In the case shown, it would be easy by just passing the game object around to functions which need it.) (在所示的情况下,只需将game对象传递给需要它的函数就很容易了。)
  • Is it possible that there isn't only one kind of such an object at a later point in time?是否有可能在以后的某个时间点不只有一种这样的物体? (For example, you may want to write an editor for levels of the game, where you want to reuse some of the code, and this editor should be capable of editing multiple games in multiple tabs.) (例如,您可能想为游戏的关卡编写一个编辑器,您想在其中重用一些代码,并且该编辑器应该能够在多个选项卡中编辑多个游戏。)
  • Does using a global harden reading the code?使用全局强化阅读代码吗? (Remember, easy to read is way more important than easy to write!) (请记住,易读比易写更重要!)

In most cases, it's better to avoid global variables, in my opinion;在我看来,在大多数情况下,最好避免使用全局变量; and I think it's better to avoid it for the case shown in the question.我认为对于问题中显示的情况最好避免它。 A game parameter can be passed around easily.可以轻松传递game参数。

In short, yes this breaks encapsulation.简而言之,是的,这打破了封装。 The fact that you keep referring to the game object reveals that you have dependencies towards this object.您一直引用游戏对象这一事实表明您对这个对象有依赖性。

You might consider of having an initialisation sequence in your program, called the composition root, (for simple examples main is the most obvious place to do this), where you pass all dependencies like this towards the objects that need them via the constructor, which is called dependency injection.你可能会考虑在你的程序中有一个初始化序列,称为组合根,(对于简单的例子, main 是最明显的地方),在那里你通过构造函数将所有像这样的依赖传递给需要它们的对象,它称为依赖注入。

If you want to go even a step further you can create base classes and pass abstract base classes instead of implementation objects.如果您想更进一步,您可以创建基类并传递抽象基类而不是实现对象。 That way you are more programming towards interfaces instead of objects.这样你就可以更多地针对接口而不是对象进行编程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM