0

I have a program I am in the middle of writing that is meant to simulate bugs finding food. In brief i have a grid (a world) in which there are bugs, obstacles and food of different energy values. Each bug will look in every direction, get the closest food within its "seeing distance" and move one cell towards it otherwise moving in a random direction.

I have 3 clases:

  • ABug

  • AWorld

  • Main

ABug and AWorld obviously contain all the methods to populate a grid with food and obstacles, sense food, move a bug etc, and the Main class is the controller that creates a world, creates a number of bugs based on user input and adds them to the world.

My question is:

Is there a better way to make a bug know about a world it is in whilst a world also knows about the bugs in it other than passing a reference of the world into every function that needs it inside a bug?

I currently have an arraylist of bugs inside the world class and then pass the 2D array into the functions that need it in the bug class.

Sorry for the long explanation, wasnt sure how much detail people would want so I just put it all :)

Thanks for any suggestions

JabbaWook
  • 677
  • 1
  • 8
  • 25
  • 1
    You can reference the World class in ABug class too but thinking about it it would just be one World so you can make it singleton ! – StackFlowed Nov 04 '14 at 15:52
  • haha sorry i wasnt sure how best to ask the question so i just put everything down @StackFlowed are there any docs on singletons? i have not used them before so could you possibly explain how they would help here? – JabbaWook Nov 04 '14 at 15:54
  • Since your Bug is in a World, you can put Bug inside a World as Worlds property. So bug will also be aware of all the other properties of the same world as long as World exist. – Jimmy Nov 04 '14 at 15:57
  • Pass a reference to the World into the constructor for the Bug, and save it? – Teepeemm Nov 04 '14 at 15:57
  • http://stackoverflow.com/questions/519520/difference-between-static-class-and-singleton-pattern – StackFlowed Nov 04 '14 at 15:58
  • So to throw a spanner in the works, does it change anything if the world is constantly changing, ie bugs moving around food being eaten etc. if the world is saved as a property in the bugs constructor then surely it wouldnt update as the world changes? – JabbaWook Nov 04 '14 at 16:07

2 Answers2

2

I would pass a reference to a World instance to every Bug Object either in the Bug constructor or in a setter Method. That way every bug instance knows it's respective world instance and can ask it about certain things (e.g. ask for food,...).

I would not make World a Singleton (definition see: http://en.wikipedia.org/wiki/Singleton_pattern). As there is no need and no use to limit yourself to exactly 1 instance of World. When used inappropriately Singleton pattern can limit the testability of your design, introduce subtle threading (and classloading) issues,...

markus
  • 1,631
  • 2
  • 17
  • 31
  • So to throw a spanner in the works, does it change anything if the world is constantly changing, ie bugs moving around food being eaten etc. if the world is saved as a property in the bugs constructor then surely it wouldnt update as the world changes? – JabbaWook Nov 04 '14 at 16:07
  • 1
    @JabbaWook It's important to remember that you are not saving separate `AWorld` objects in each bug, but rather each bug is saving a reference to the one `AWorld` object. – DoubleDouble Nov 04 '14 at 16:10
  • Thanks for that clarification! @JabbaWook: If your world is supposed to notify the bugs about changes in their environment you could use somekind of publish/subsribe mechanism where the bugs register callbacks for your world to inform them about changes. – markus Nov 04 '14 at 16:12
  • @DoubleDouble oh of course. completely forgot that, still getting used to the whole passing by reference thing. Thank you! – JabbaWook Nov 04 '14 at 16:13
  • @markus Im using a tick based system, so on every "tick" the bugs look for food based on the current world and then update the world array with their new position. at the end of each "tick" I just print the world array. The bugs dont react to a change in their environment, more just analyse it periodically. – JabbaWook Nov 04 '14 at 16:16
  • @JabbaWook: Okay then its the other way round. Just remember your bugs have reference the same instance of world (even though you shouldn't use Singleton imho). – markus Nov 04 '14 at 16:18
  • @JabbaWook I may have used the wrong semantics though. It is actually pass by value, [See link for possible clarification (or just confusion)](http://stackoverflow.com/a/73021/2974766). Personally, it makes my head hurt. – DoubleDouble Nov 04 '14 at 16:19
  • 1
    @DoubleDouble thanks for the link "java passes objects by reference, but those references are passed by value" haha makes my head hurt too! – JabbaWook Nov 04 '14 at 16:26
  • 2
    @jabbawook: it is probably less confusing if you look at it that way. In java everything (except primitives like int) is a reference (similiar to a pointer in other languages). When calling a method all parameters are just references. These references are copied when a method is called however the actual objects these references are pointing to are not copied. – markus Nov 04 '14 at 17:31
1

Instead of passing World with every Bug-method as a parameter, you can also just do it once in a Bug's constructor and save it in a variable-field of ABug, like so:

In Main:

public static void main(String[] args){
    AWorld world = new AWorld(...);
    ABug[] bugs = new ABug[amount];
    for(int i = 0; i < amount; i++)
        bugs[0] = new ABug(..., world);
}

In ABug:

private AWorld world;

public ABug(..., AWorld w){
    this.world = w;
    ...
}

public void someMethodNeedingWorld(...){
    world.methodYouNeedFromWorld();
    ...
}

You can also try what #StackFlowed said and make AWorld a Singleton:

In AWorld:

private static AWorld instance;

private AWorld(){ } // private constructor for Singleton pattern

public static AWorld getInstance(){
    if(instance == null)
        instance = new AWorld();

    return instance;
}

In Main:

public static void main(String[] args){
    ABug[] bugs = new ABug[amount];
    for(int i = 0; i < amount; i++)
        bugs[0] = new ABug(...);
}

In ABug's methods where you need AWorld:

public void someMethodNeedingWorld(...){
    AWorld.getInstance().methodYouNeedFromWorld();
    ...
}

Personally I would go for the Singleton pattern, since this is what they are designed for. This also makes sure you only have a single AWorld instance during your entire application. (If you want to be able to create multiple Worlds at some state, I would suggest the first method.)

EDIT:

If you want to make future adjustments by having multiple AWorlds in the same application, or use UnitTests, the Singleton Pattern isn't a very good idea, since it can only work with 1 AWorld-instance at a time, doesn't matter if its a UnitTest or not. So in that case, I recommend the first option, by just sending the AWorld object to the ABug's constructor and saving it in ABug, instead of sending it as parameter with every method of ABug. Still, if you never want to use UnitTests or make adjustments (can't recommend that, but it's up to you..), the Singleton Pattern could be used here.

Kevin Cruijssen
  • 9,153
  • 9
  • 61
  • 135
  • 1
    Kevin i don't even need to compile your code for singleton .... it will throw an comply error cannot reference non static in static method. – StackFlowed Nov 04 '14 at 16:04
  • @StackFlowed Ah, you're right. Fixed – Kevin Cruijssen Nov 04 '14 at 16:07
  • 1
    @Kevin: Sorry I wouldn't go for the Singleton here as a.) there is no use/need and b.) the testability of your design is reduced by the singleton. Suppose you want to introduce a World Mock-Object for Unit Tests. You can't just replace the real World Object with a Mock because it's hardwired in your Bug class. That's where inversion of control comes into play (http://en.wikipedia.org/wiki/Inversion_of_control). If your Bug objects get a World Object set from outside than you can easily create different implementations for World that your Bugs can use. – markus Nov 04 '14 at 16:09
  • @markus You're indeed right. I also tend to use the Singleton Design Pattern less myself, so it's easier to make future adjustments. Let's say OP wants to have multiple Worlds in the future, this isn't possible with a Singleton Pattern. And indeed, like you said, it's also not possible for parallel UnitTests and normal build at the same time, only one by one because you replace the Singleton's instance in the UnitTests. I just added it as an option, so the OP is free to choose what suits his code best. – Kevin Cruijssen Nov 05 '14 at 08:10
  • 1
    @KevinCruijssen: Thanks for your comment. I personally found Singletons quite tempting when starting out as a developer, put a lot of stuff in Singletons and ended up with almost everything depending on the "bloody" singleton in the end. It took me quite some time to disentangle my codebase. So I learnt it the hard way:-) – markus Nov 05 '14 at 16:23