I'm a pretty seasoned procedural programmer who only quite recently made the jump to an object-oriented language (Java and C#) and I am having a very hard time understanding how global objects are commonly handled.
For instance, I have a multiplayer game that allows up to 4 players to connect to a server. I have an object with all its methods, etc... I create a new player object instance when a new player connects, but how can I carry these instances over to other source files?
Usually, you try to avoid global objects. If you need to use a player object in some method, pass it by reference to the method. For example
class Player {
public void someMethod() {}
}
class Controller {
public void usePlayer(Player p) {
p.someMethod();
}
}
class Game {
static int Main(string[] args) {
Player p1 = new Player();
Controller c = new Controller();
while (gameRuns) {
if (someCondition) {
c.usePlayer(p1);
}
}
return 0;
}
}
as a reference would be one way
that's just pseudo javaish code.
class Main {
private playerMap: playerMap;
public void main(args[]) {
final child ChildClass = new ChildClass(this.playerMap);
child.doSomethingWithPlayers();
}
}
the main thing about object orientation is control over the messaging "what gets passed to whom and how can it be accessed".
there are different patterns to work with but passing a reference is an easy approach.
You can also look at the Singleton pattern, that gives the option for global functionality without breaking OOP
Avoid global objects at all costs, don't be tempted to start using static classes, variables and methods either to mimic the use of global objects in code. Read about the perils of static classes, methods and variables here . Read about the code smell static cling here .
Spend some time acquainting yourself with Object Orientated Programming best practices and Code smells. Global variables and objects are a code smell.
What you need to think about is designing services in your application with Dependency Injection in mind so that you can manage the lifetime of these services effectively. Typically you would need to develop your application to be loosely coupled so that you can utilise Dependency Injection and a Dependency Injection Container to manage the lifetime of the services the application provides. This would normally involve a class with a method call called the composition root that composes all the objects in the application.
The Dependency Injection Container if you choose to use one can be configured to deal with all the dependencies in the application and manage their lifetimes. Example Lifetime scopes are Singleton(Return a single instance of an object every time it needs to be used), Transient and others that take into consideration concurrency. If a Dependency Injection Container is too much complexity for your application you can compose and manage object lifecycles yourself in code.
There should be no need for global variables or objects in an Object Orientated Application. To save you time and effort start thinking regarding the best practices of OOP from now on in the way you write and structure code:
+SOLID principles +Clean Code and Architecture - Robert C Martin +Acquaint yourself with and learn about Code Smells and how to avoid them.
ags
Matt Strom
Software Engineer, TypeScript ninja
A more advanced technique is to use a dependency injection library, such as Autofac for C#, Spring for Java, or Inversify for TypeScript. When using a DI container, the container is responsible for filling references in constructors with the appropriate values.
An example in TypeScript using Inversify:
let container = new Container(); container.bind<GlobalObject>().to(GlobalObject).inSingletonScope(); @injectable() class InstanceObject { constructor(@inject(GlobalObject) globalObject) { } } let instance1 = container.get<InstanceObject>(); let instance2 = container.get<InstanceObject>();At the end the code will have constructed two new objects,
instance1andinstance2, which both have references to the global object without needing to be manually wired up.This is a simple case for which dependency injection is overkill, but with larger applications, DI becomes indispensable.