riciloma
riciloma

Reputation: 1834

How to organize object repeated in various classes? Java

I'm developing a basic card game in Java, and I've prepared a set of Managers subclasses that interact between themselves (like PlayerManager interacting with DeckManager) However, to achieve this I would need to put a Manager inside every class that needs it. So, for example:

if PlayerManager needs to a card from a deck --> executes drawCard() inside DeckManager,
so inside PlayerManager there's a DeckManager object.

The problem is that I don't if it's the correct way to proceed, because everytime a Manager needs another one, I would have to create the needed manager inside the one who needs it.

Is there a better way? I thought of doing a class that contains all the Managers and make it static, but I don't know if it's good or not in Java.

Upvotes: 1

Views: 141

Answers (5)

Marcin D
Marcin D

Reputation: 916

A simple solution would be to use the singleton pattern

In your manager class have a method that returns the instance of that class if it exists, if not the object is instantiated.

public static synchronized Manager getInstance()
    {
        if (instance == null)
            instance = new Singleton();

        return instance;
    }

Then you can call any method on that object that belongs to the class.

source: http://www.oodesign.com/singleton-pattern.html

Upvotes: 0

Brett Kail
Brett Kail

Reputation: 33936

Singletons are not recommended. They prevent multiple instances from running in the same process (which might not be important for your use-case, but generally speaking), and they make it harder to unittest (you can't mock the DeckManager instance, which means the testing of those two classes are coupled and can't be tested independently).

Typically, you would pass the manager to the object as it's being created. For example, if you have a Game object with DeckManager, it could create each PlayerManager and pass itself (or the DeckManager) to that object's constructor.

Upvotes: 5

bm1729
bm1729

Reputation: 2375

Sounds like dependency injection would solve your problem. Dependency injection is the practice of having the dependencies of an object injected into it (via setter or constructor typically). A dependency injection framework (such as Spring) can help manage this for you. Consider the following (the annotations are for the benefit of spring autowiring - check internet for more details :) )

@Component
public class DeckManager implements IDeckManager {
    public Card drawCard() {
        // Implementation here
    }
}

@Component
public class PlayerManager implements IPlayerManager {

    private IDeckManager deckManager;

    @Autowired
    public PlayerManager(IDeckManager deckManager) {
        this.deckManager = deckManager;
    }

    public void doSomething() {
        this.deckManager.drawCard();
    }
}

Spring would create you a DeckManager, notice that PlayerManager requires one to be created and inject it via the constructor.

Programming in this way is preferable to creating the instance of the DeckManager in PlayerManager because it creates loosely coupled code which is easier to test (amongst other benefits).

Upvotes: 2

StuPointerException
StuPointerException

Reputation: 7267

You should look into the Singleton pattern to solve this problem, there will then be a single instance of each manager that can be 'injected' into any other manager that needs access to it:

public class MyManager {

    private static MyManager singleton = new MyManager();

    /* Prevent instantiation
     */
    private MyManager() {
    }

    /* return single instance */
    public static MyManager getInstance() {
        return singleton;
    }
}

Injected as follows:

public class MyOtherManager {
    private MyManager = MyManager.instance();
}

This is a very common pattern in service oriented design (I assume your managers are your service tier).

Upvotes: 1

OldCurmudgeon
OldCurmudgeon

Reputation: 65811

You may be tempted to use the Singleton pattern. By all means do so if you must, but there are alternatives.

Consider creating a new class that does the interaction for you. When you realise that there is a natural name for this object then you will know you are doing the right thing.

Here I've created a new class called Game which should allow you to do the interactions where they are appropriate. Notice now that we could have multiple Games going on at once.

class Player {

}

class Deck {

    private void shuffle() {

    }

}

class PlayerManager {

    final Collection<Player> players;

    public PlayerManager(Collection<Player> players) {
        this.players = players;
    }

    private Collection<Player> getPlayers() {
        return players;
    }
}

class DeckManager {

    final Collection<Deck> decks;

    public DeckManager(Collection<Deck> decks) {
        this.decks = decks;
    }

    private void shuffle() {
        for ( Deck deck : decks ) {
            deck.shuffle();
        }
    }

    private void deal(Collection<Player> players) {

    }
}

class Game {

    final PlayerManager players;
    final DeckManager decks;

    public Game() {
        players = new PlayerManager(makePlayers());
        decks = new DeckManager(makeDecks());
    }

    private Collection makePlayers() {
        return null;
    }

    private Collection<Deck> makeDecks() {
        return null;
    }

    public void shuffleAndDeal() {
        // Shuff all decks.
        decks.shuffle();
        // Deal to players.
        decks.deal(players.getPlayers());
    }
}

Upvotes: 1

Related Questions