1

I have a probably minor application design (and maybe understanding) problem. Please forgive me if the following problem is quite noob-like. I just started learning Java three weeks ago and didn't find a proper answer to my problem.

Situation: I am trying to bring an old pub game into a digitized version with Java and JavaFX for the UI. I am using an MVC design, whereas I use the controller to initiate the start of the game by a user click. Then the controllers do all the prep-actions for the game. One important part is creating n (number of players) objects from a class Player and writing them into a HashMap. And here probably starts the design issue: The Map and its referred objects hold all the core game information of the players. Thus I almost always hand over the Map between the methods from the controller and the model so that I can always reuse the info in the Map. Now I am at the point, where the initial program/game board set-up is done and the game needs to wait for a user input where the user presses a button.

Tried/Idea: I initially thought that I could put any method as OnAction on the button and then continue from there. But since all my methods require the Map as an input parameter I cannot put the method as OnAction for the button (in SceneBuilder).

Problem: Actually the problem is (as far as I see it), that I don't have the Map (which is my central data storage an which is updated by the various methods and shall be updated by the user actions) centrally and "method independent". So since I want to call a method from a user click, and thus the method is independent of any "program flow", how to get access here to my Map to update the data accordingly and reuse the Map in the subsequent program.

As said I think there is a super easy solution for this problem and probably I don't get one of the basic concepts in detail but I hope I could explain my issue in an understandable way.

SecretAgentMan
  • 2,856
  • 7
  • 21
  • 41
  • Why don't you use a public getInstance singleton method for that? – Ssr1369 Jan 16 '20 at 10:42
  • as-is, the question is waaayyy too broad and as such off scope for this site – kleopatra Jan 16 '20 at 10:45
  • 4
    You are probably misusing Map. My guess is that your program is a catastrophe of get and put statements. Why not just create a class with fields and use that instead of the map? – rghome Jan 16 '20 at 10:45
  • Pass the map to class through constructor once instead of passing it again and again in methods. – Azodious Jan 16 '20 at 10:47
  • 1
    The Map is the M in MVC, the data model. In general the Controller could be a singleton, globally accessible everywhere. And via the controller you could access/change data. `Controller.getInstance().setN(42);` The controller then might set Views appropiately. – Joop Eggen Jan 16 '20 at 10:48
  • I think it will be useful to add a sample code of your case. Since ```onAction()``` takes an ```EventHandler``` instance the issue should be easily resolved using lamdas. Also, is it possible to add a dynamically specified ```EventHandler``` in SceneBuilder? – Sree Kumar Jan 16 '20 at 11:06
  • @rghome: Yeah I think you are right. Actually I just used to Map to keep the creation of the player object instances dynamic (number of players). So I create n instances of Player() in a for-loop and put the Player instances into the value column of the Map. The key of the Map is a String equal to player1, player2, etc. – SimonTheSorcerer Jan 16 '20 at 12:55
  • @SimonTheSorcerer it sounds like you want an array or a List for that. – rghome Jan 16 '20 at 13:22

1 Answers1

3

The term you are looking for is Cohesion.

Cohesion is a measure of how the methods of a class or a module are meaningfully and strongly related and how focused they are in providing a well-defined purpose to the system. Check this for more information.

Let's take a look at this class:

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class FileMetadataExtractor {
    public FileMetadataExtractor() {
    }

    private Date extractLastModificationDate(File file) {
        return new Date(file.lastModified());
    }

    private String extractFileName(File file) {
        return file.getName();
    }

    private String extractExtension(File file) {
        String fileName = extractFileName(file);
        int i = fileName.lastIndexOf('.');
        String extension = "";
        if (i > 0) {
            extension = fileName.substring(i+1);
        }
        return extension;
    }

    public Map<String, String> extractMetadata(File file) {
        String name = extractFileName(file);
        String lastModified = String.valueOf(extractLastModificationDate(file));
        Map<String, String> metadata = new HashMap<>();
        metadata.put("file_name", name);
        metadata.put("last_modified", lastModified);
        metadata.put("extension", extractExtension(file));
        return metadata;
    }
}

From what I understood, this class looks like your class. This class low cohesion. It means that the class doesn't focus on the goal it was created for and the members of this class has a loose relationship. The higher the cohesion, the better the class can do its job.

Now let's take a look at another version of that class:

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class FileMetadataExtractor {
    private final File file;

    public FileMetadataExtractor(File file) {
        this.file = file;
    }

    private Date extractLastModificationDate() {
        return new Date(file.lastModified());
    }

    private String extractFileName() {
        return file.getName();
    }

    private String extractExtension() {
        String fileName = extractFileName();
        int i = fileName.lastIndexOf('.');
        String extension = "";
        if (i > 0) {
            extension = fileName.substring(i+1);
        }
        return extension;
    }

    public Map<String, String> extractMetadata() {
        String name = extractFileName();
        String lastModified = String.valueOf(extractLastModificationDate());
        Map<String, String> metadata = new HashMap<>();
        metadata.put("file_name", name);
        metadata.put("last_modified", lastModified);
        metadata.put("extension", extractExtension());
        return metadata;
    }
}

Now, the relationship between the members and methods of this class is tight, and the class needs a File instance only one time to make all the other methods work. You can do the same in your class and share the members that other methods or members will use.

Please read this thread about cohesion and coupling for more information.

Miss Chanandler Bong
  • 4,081
  • 10
  • 26
  • 36