• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Using globals in code

 
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am writing a piece of software to display an image on the screen using a particular library. The library lets me create an Atlas out of texture file data, to fetch Textures out of the Atlas using the textures' names, and to draw the textures by calling Renderer.draw(texture). It doesn't make a great deal of sense to create more than one of an Atlas or Renderer.

I previously designed my code as follows:



Similarly, I made a TextureRenderer class whose sole purpose is to provide static access to a Renderer. But many people seem to say that opening up a class like this to global access is bad. I cannot think of any better alternative, however. My core update/draw logic currently works something like this:



Making a Renderer object belong to the Game or Screen class doesn't make much sense to me, as there doesn't seem to really be a 'has-a' relationship between them; it's more of a 'uses-a', so that seems to imply that it would be best to just call Renderer.draw(thing) from outside the class rather than making it a data member. This would make my main code essentially call the various methods in order to get or print some form of data, much like System.out.println(). And of course, making one of the classes a subclass of Renderer makes even less sense. But making data members static for the purpose of global access and using singletons are often cited as 'bad' programming practices. This problem also arises in a lot of other scenarios in my program, ie. when I want to serialize Thing data members like texture filenames; do I put the serializer as a static data member in a class for global access and call it like I would a function, or do I put it in a class? And it seems like the Renderer will have to be initialized at the start of the program, which would take place in the init() method in Game, then be used to draw Textures in the Screen, so it would have to be accessible from both locations. How should I approach these scenarios?

edit: In case it's suggested to put these in the main class, that's unfortunately going to be difficult without using static variables; the library recommends having the main class creating an Application object, which is essentially a black box that actually does all the work of calling Game's init() and draw() methods (via a Game object passed into its constructor) and looping until the program exits. AbstractGame and Screen are classes supplied by the library, so it doesn't seem like I can easily give Game any data that AbstractGame doesn't specifically ask for.
 
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There are a number of reasons for wanting to avoid global statics: global statics and testability

Using "has-a" to think about object relationships can be useful at times but I don't think your take on "has-a" vs "uses-a" is helping you in this case. It might help if you think about it in terms of "A collaborates with B" instead. An object will typically hold references to other objects that it will collaborate with to do some work. For example, a business service object may define a workflow that involves calling one or more domain objects and/or one or more infrastructure objects. That is, a Transfer service may call on two Account objects, an AccountDao (data access object), and a Notifier object to complete a balance transfer transaction. Here, a "has-a" view on object relationships might lead you to think that it's not appropriate for a Transfer object to hold a reference to a Notifier even though there's really nothing wrong with it. I think using dependency injection helped me make the leap in understanding the difference.

That's one pitfall of object-oriented programming that you'll need to learn to avoid early on: object-oriented thinking is not about modeling your software objects after real-world objects; it's about assigning responsibilities appropriately. Thinking in terms of real-world objects can help you organize your thoughts but in the end, proper OO design is about encapsulating what each object is responsible for "knowing" (its data members) and "doing" (its methods).
 
Jack Franz
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That's definitely an approach I never considered. I'll try to focus more on knowing and doing when designing my code, as opposed to has-a/is-a relationships; the former seems more complicated and open-ended, but hopefully I can get acquainted with that way of thought more as I practice. Dependency injection also seems interesting, and I'll try to think about my services in that way more often.

Thanks for the information!
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jack Franz wrote:edit: In case it's suggested to put these in the main class, that's unfortunately going to be difficult without using static variables


Unless you define them in the method itself. Most of the time, main() methods are simply used as "launchers", so they should contain only as much code as is needed to initialize required stuff and then pass it off to an instance (possibly of the class containing main()), which then does everything else. One very basic technique is described in the MainIsAPain page; although it's mainly meant for greenhorns to get them out of the habit of ploughing all their code into main(). You still might find it worth a read.

Making a Renderer object belong to the Game or Screen class doesn't make much sense to me, as there doesn't seem to really be a 'has-a' relationship between them; it's more of a 'uses-a'...


But couldn't you say the same thing about a program and a database? And yet these days they're generally established via a DataSource (javax.sql.DataSource) object, rather than a static DriverManager definition.

This idea of a factory object that returns an interface is used quite a lot for these kinds of "heavyweight" objects that tend to only be initialized once and then used a lot, but forcing it via a static class, or a singleton, tends to cause more problems than it solves.

For one thing, if you come up with (or find) a better "Renderer" in the future, it allows you to plug it in with the minimum of effort.

HIH

Winston
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic