Jump to content

  • Log In with Google      Sign In   
  • Create Account


EDI

Member Since 05 Jan 2002
Offline Last Active Today, 06:54 PM
****-

Posts I've Made

In Topic: Anybody left from the 2003 crowd?

21 October 2013 - 08:47 AM

Did somebody say 2003 crowd!?


In Topic: questions about singletons

29 August 2013 - 09:07 PM

LPD3DXTEXTURE tex[maxtextures];

 

Zsettexture(tex[texID]);

 

i should have something like:

 

LPD3DXTEXTURE p;

texDB.gettex(&p);

Zsettexture(p);

 

or better yet:

texDB.settexture(texID)

 

although internally, set texture is a d3d device pointer method, perhaps leading to (the possibly over-engineered - over abstracted):

D3Ddevice.settex(texID)   and the "database" of textures is  part of the D3Ddevice object, 'cause that's the object that actually uses the data. 

 

over-engineered, or did i just have an insight? <g>

 

 

Certainly if you desire to have an object that holds textures; it might be:

 

texDB->addTexture(id, pTexture);

 

then later

 

tex=texDB->getTexture(id);

 

these two methods form an interface, with that interface I as another developer can replace your implementation with another that functions different internally; without upsetting any other code.

 

 

As for:

 

D3Ddevice.settex(texID)

 

i would assume that is a static method off of a class;

 

instead you should have an instance of a D3DDevice

 

D3DDevice* device=new D3DDevice(/*params require for instantiation*/);

 

device->setTexture(tex);


In Topic: questions about singletons

29 August 2013 - 12:21 PM

 

Singleton as a "one and only one" instance enforcement

 

This is better handled with standard object construction / destruction; if there should only be one instance of an object in your program, instantiate only one.

 

If your code would break because more than one object has been instantiated that is a big problem that should be solved.

 

 

I mostly agree with what you've said, but in this case I'd point out that the only time I use a singleton is when I inherit this kind of problem from an external library. I actually had that problem crop up in class last semester, where a library we were using abstracted all resources and forced us to refer to everything by assigning it an integer handle. I created a singleton to function as a kind of handle distributor. It contained an internal int that started at 1 (the lowest allowed value for the int handles) and it had a method that would return that and increment it. If there were ever two instances of this class then all of my resources would potentially be invalidated because their handles could suddenly be used to load a new resource. My whole motivation in creating the singleton was to enforce one-and-only-one instance.

 

 

That is a poorly designed library, or your understanding of the API might be incomplete.

 

Such libraries exist where they are just calls to 'getNextResource', virtualizing this across multiple objects can be tricky.

 

The simplest case of this is C or C++ 'rand()' function, it uses an internal PRN sequence

 

While not ideal, you could manage this using srand() to set the seed to the known instanced value before a call to the global rand()

 

Some libraries provide similar functionality, specifying a 'context' or 'device' id for the global functions, which partitions sets of identical resource id's.

 

If the library had such a feature you could have your 'Singleton' instance, hold and use the device id.

 

If the library did not support such a thing, time to go bitch them out, they're writing broken code.

 

 

Thanks for posting this example, as it is another common reason people turn to singletons, to help shield against code like this.


In Topic: questions about singletons

29 August 2013 - 09:25 AM

and therefore don't really understand why people hate them.

 
People hate global variables for three reasons:

  • access to information from anywhere without formal declaration of collaboration means you can't adequately control or change how sections of code are connected.
  • global variables represent application-lifetime information, in order to adequately 'reset' your program, for testing or say a 'new game' you have to manually 'drive' these values to a known good state, instead of them being destroyed naturally as part of an object graph.
  • global variables are often 'autos' and the construction order of file-scope/static automatic variables is not sanely controllable

i use them is very specific ways only - ways which i'm hard pressed to find a better solution for

 

Look into dependecy injection.

 

guns don't kill people, people kill people.

 

Unless your gun and ammo was made by you, unsafe, and blows up at the shooting range.

 

i mean am i supposed to use a setter and getter for everything?

In short, yes; your public accessable interface should be well defined; reaching into an object for various internals is violating proper usage of a class.

But this is less of an issue than using globals.


In Topic: questions about singletons

28 August 2013 - 10:31 PM

Lot's of folks here have answered the questions well but I thought I'd throw my hat into the ring as well:

Singleton as a "one and only one" instance enforcement

 

This is better handled with standard object construction / destruction; if there should only be one instance of an object in your program, instantiate only one.

 

If your code would break because more than one object has been instantiated that is a big problem that should be solved.

 

In theory properly designed code should not care about instances created in isolation, instances only become useful when associated with other instances or directly acted upon.

 

 

Singleton as a global point of access

 

Many people use singletons for the ability to access features from various points in their program; this is a huge design flaw.

 

By making a direct reference to say "TextureManager::getInstance()" you have failed to properly declare your collaborators from the accessing class.

 

Collaborators should be explicitly declared either via constructor parameters (for required objects for normal baseline functionality) or via setters for optional functionality.

 

This explicit declaration and requiring to pass instances to other instances, forms your object graph, the ability to construct and destroy your object graph without any residual state, is hugely important for testing, and avoiding flaky behavior.

 

"I can't go around passing instances into objects, that's too tedious and I don't know all the places I want to use my object"

 

First off, the excuse of not wanting to explicitly declare what objects can operate on other objects is laziness; and will lead to bugs, hard refactoring, "spaghetti" code smell, and will make it harder to see and understand good design choices from poor ones.

 

Many developers provide the scenario that, when creating an object from within another object, they may not have the instance they need to construct that object.

 

The problem with this scenario is deeper than the problem suggested however, if you have objects deep in your object graph creating other objects; you've already lost the battle.

 

You should take steps to have top-level code, such as a Factory, build and construct objects according to a design specification (such as loaded game data), these objects then work when assembled properly and have no concern about how they were joined together.

 

Consider the example of a Car object, within its constructor it creates an Engine, and four Wheel objects.

 

You would rightly assume that the Car constructor would need all the parameters that the Engine and Wheel objects require, putting a considerable number of confusing parameters into the Car constructor.

 

e.g: Car(color, horsePower, rpmRedLine, whiteWalls, treadPattern);

 

If instead you have a CarFactory object, take in such information, it can then create Car, Engine and Wheel objects in isolation, and join them together based on specification in CarFactory.

 

This keeps specification and implementation of Car, Engine and Wheel light; and allows for Substituting of subclasses if required; which would not be possible if Car's constructor were doing the 'new' ing.


PARTNERS