0

So im having a problem on my game because i cant figure out how to handle my Explosion ArrayList since i need to add elements to it from several different places, and while searching a solution to this, i came up with a very messy solution which would be:

import java.util.ArrayList;


public final class Factory {

    private static ArrayList<Explosion> booms = new ArrayList<Explosion>();

    public static void addBoom()
    {
        booms.add(new Explosion());
    }

    public static ArrayList<Integer> getBooms() {return booms;}
}

I know, it looks awful, but how awful is it? My question is if this is a viable solution or just plain silly and why would it be such. Yes, im making it global (i guess) but its not the worse global there is or is it?

Xkynar
  • 935
  • 1
  • 10
  • 31
  • I dont understand what you are trying to do. Why cant you just used an `ArrayList` by itself (without wrapping it in a class)? If it comes from several different places just put it in a high scope. – David says Reinstate Monica Sep 30 '13 at 22:14

4 Answers4

2

A more elegant solution would be to make the class a Singleton, which is a design pattern made to do essentially what you want, but more elegantly.

this is an article that outlines how to create a singleton.

Michael Hoyle
  • 249
  • 2
  • 9
  • Necessary disclaimer: [Singletons are evil](http://stackoverflow.com/q/137975/829571)... – assylias Sep 30 '13 at 22:41
  • -1 I see no advantage to a singleton here. The class does not implement any interfaces nor extend any abstract classes, so polymorphism is impossible. The only way to get at the single instance is via a static method. No matter what, you are coupled directly to the class, so why not cut to the chase and use static methods? – Brandon Sep 30 '13 at 22:58
1

Instead of an ugly global state (or singleton which is just a fancy way of doing the same), I would use a dependency injection pattern by having a simple BoomState object:

class BoomState {
    private final List<Explosion> booms = new ArrayList<Explosion>();

    public void addBoom() {
        booms.add(new Explosion());
    }

    public List<Explosion> getBooms() {return Collections.unmodifiableList(booms);}
}

and pass it around to whoever needs it.

Note that this is not thread safe so needs to be amended if accessed by more than one thread, for example by using a CopyOnWriteArrayList.


One alternative would be to use an Observer pattern. Your BoomState would keep a list of "live" bullets and "listen" to the bullet state and update the booms list when a bullet state changes to EXPLODED. Something like:

class BoomState {
    private final List<Explosion> booms = new ArrayList<Explosion>();
    private final Set<Bullet> liveBullets = new HashSet<Bullet>();

    // to be called by your weapon or bullet factory
    public void addLiveBullet(final Bullet bullet) {
        liveBullets.add(bullet);
        bullet.onExplode(new Runnable() {
            @Override public void run() {
                addBoom();
                liveBullets.remove(bullet);
            }
        });
    }

    public void addBoom() {...}
    public List<Explosion> getBooms() {...}
}

And you bullet:

class Bullet {
    private final List<Runnable> onExplode = ...
    public void onExplode(Runnable r) { onExplode.add(r); }

    public void doExplode() {
        //show some colours
        for (Runnable r : onExplode) r.run();
    }
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • My fear is that this solution would force me to make chain-passings of the single object. For example, i wanna make explosive bullets. That would mean every RPG (the explosive bullet) i create must have a pointer to this object. But these bullets would be shot by a Weapon object (which would be in RPG-Launcher on that moment, since its the only weapon that launches RPGs) which resides inside of every mob that holds a weapon, and since i have my object arrays in the Level class, creating the boomstate object in level would force me to send its pointer to the player, which would send it... – Xkynar Sep 30 '13 at 22:47
  • ... to his rpg-launcher, which would send it to the rpg bullets, and the same goes for every mob : ( – Xkynar Sep 30 '13 at 22:47
  • You just taught me how to create event handlers too so thank you alot xD <3 – Xkynar Sep 30 '13 at 23:41
  • Actually can you explain me what is the private final List onExplode = ... for in bullet? Why a list for each bullet? – Xkynar Oct 01 '13 at 00:21
  • @user2295607 if there is never more than one object listening to the bullet explosion (the BoomState in my example) you can just store a `Runnable onExplode` indeed. If there can be more than one listener then you use a list. – assylias Oct 01 '13 at 06:26
  • Am i supposed to instanciate an object of the BoomState class or should i use it as a final class? – Xkynar Oct 01 '13 at 08:07
  • Not sure why you mention final class (it just means that it can't be sub classed) - yes you can create one instance at a high level in your code, for example when you initialise all your large objects when your app starts. – assylias Oct 01 '13 at 08:12
  • Sorry i ment use it as static methods so i dont have to initiate an object and just call it by BoomState.addLiveBullet(...), im just confused on how to add a new bullet, the addLiveBullet method might be a little hard to access – Xkynar Oct 01 '13 at 08:16
  • The whole point was to avoid static/global state. How to do it depends a lot on your whole architecture. If you find it hard to implement without static, it probably means that there is too much coupling in your design - in that case it will be easier to use a static class or a singleton and you should go with what you put in your question or one of the other answers. – assylias Oct 01 '13 at 08:21
  • I understand but if in the end i end up passing this new object in a train so that bullets can be added, it doesnt solve the initial problem :/ I know the problem is in my architecture, im trying to find the best way to refactor it, thats all – Xkynar Oct 01 '13 at 09:27
0

If you want to modify booms from diferent places, you should use Vector instead of ArrayList. It is similar to ArrayList but synchronized ;-) http://docs.oracle.com/javase/6/docs/api/java/util/Vector.html

angel_navarro
  • 1,757
  • 10
  • 11
  • I actually am using Vectors but i thought arraylists were very loved by the java community so i just went with the rest of the sheeps xD – Xkynar Sep 30 '13 at 22:24
  • 2
    Vector is obsolete. There are better ways such as `Collections.synchronizedList(new ArrayList())` and `CopyOnWriteArrayList` for example. – assylias Sep 30 '13 at 22:58
  • Thanks for your comment, I didn't know it ;-) – angel_navarro Oct 01 '13 at 06:58
0

Use Singleton pattern to have just one instance which state you can access anywhere.-

public class YourSingletonClass {
    private static YourSingletonClass singleton;

    private ArrayList<Explosion> booms;

    private YourSingletonClass() {
        booms = new ArrayList<Explosion>();
    }

    public static YourSingletonClass getInstance() {
        if (singleton == null) {
            singleton = new YourSingletonClass();
        }
        return singleton;
    }

    public void addBoom() {
        booms.add(new Explosion());
    }

    public ArrayList<Integer> getBooms() {
        return booms;
    }
ssantos
  • 16,001
  • 7
  • 50
  • 70
  • Why? What is the advantage to a singleton for a class which does not implement any abstract types? – Brandon Sep 30 '13 at 23:07