3

I have around 30 not-changing "objects" (the amount of them is final, no more can be added or removed). Each object has an id as well as some booleans describing what the object is and what it isn't. Now, each objects has a variable that must be changed at runtime. Most of these variables are just an integer, but some also have strings, lists, etc.

Now I'm wondering how to implement this. My current attempt is an enum with the given objects, their properties and methods to change them (for the variable I chose just object as type, to store both integers and lists). It works, but it doesn't feel like the proper, OO-way to do this. What are the alternatives? The programming language is Java, if that matters.

Here's my attempt (a bit more complicated than what I explained above):

public enum StatusInfos {

    THING_1("id0", false ,false, false, NOT_UPGRADABLE),

    THING_1_WITH_HAT("id1", true, false, false, NOT_UPGRADABLE),
    ANOTHER_THING("id2", false, false, false, NOT_UPGRADABLE),
    GREEN_THING("id3", true, false, false, NOT_UPGRADABLE),
    TALKING_DUCK("id4", true, false, false, NOT_UPGRADABLE);


    private final String id;
    private final Boolean hasAdditionalValue;
    private Double value;
    private Double additionalValue;
    private boolean needsDouble;
    private boolean needsPerCent;


    private Integer upgradeCategory;

    private Object additionalValue;

    StatusInfos(String id, Boolean hasAdditionalValue, boolean needsDouble, boolean needsPerCent, Integer upgradeCategory){
        this.id = tag;
        this.hasAdditionalValue = hasAdditionalValue;
        this.needsDouble = needsDouble;
        this.needsPerCent = needsPerCent;
        this.upgradeCategory = upgradeCategory;
    }


    public String id(){
        return id;
    }
    public Double value(){
        return value;
    }
    public void setValue(Double value){
        this.value = value;
    }
    public boolean hasAdditionalValue(){
        return hasAdditionalValue;
    }

    public Double additionalValue(){
        return additionalValue;
    }
    public void setAdditionalValue(Double newAdditionalValue){
        additionalValue = newAdditionalValue;
    }
    public boolean hasSpecialValue(){
        return false;
    }

    public Object specialValue(){
        return null;
    }
    public void setSpecialValue(Object newValue){
        return;
    }

    public boolean needsNumbersAfterComma(){
        return needsDouble;
    }

    public boolean needsPerCent(){
        return needsPerCent;
    }

    public Integer getUpgradeCategory() {
        return upgradeCategory;
    }

    public Object getAdditionalValue(){
       return additionalValue;
    }
    public void setAdditionalValue(Object additionalValue)
       this.additionalValue = additionalValue;
    }
}
7
  • Why do you need to store an integer or a list? What’s that variable that you have to change at runtime, and why? Can you post the code that you already have? May 19, 2016 at 13:15
  • You could code a script (in Python, shell, awk, ...) to emit the Java code for you May 19, 2016 at 13:16
  • @Paramaeleon In the enum, I define a variable for all objects. because most objects store an integer in that variable and some lists, the variable needs to be of type Object. I'm gonna add some example code, maybe it'll clarify what I mean
    – Namnodorel
    May 19, 2016 at 13:25
  • Your objects do not really seem to have something in common. Why do you want to force them to have something common at all? May 19, 2016 at 13:54
  • @BasileStarynkevitch The problem is not to write the code, but to write it in a good coding style
    – Namnodorel
    May 19, 2016 at 13:57

3 Answers 3

3

I'd define a class containing all of the common stuff (is the list of booleans the same among these objects?) and their getters and setters, then subclass depending on the type of the changeable item within, then put them all into a container optimized for how you look up these things (id, probably).

This way, you have one global.

1
  • Could you edit and supply a small code snippet?
    – Dibbeke
    May 20, 2016 at 7:16
1

For me you have 2 way :

  • A registry : a class that will contains all your global variable from itself and will have getter on read-only proerty and getter/setter on read/write property.
  • Use a framework that provides dependency injection, for instance Spring. By default every bean instantiated by Spring are singleton and you can inject them (by constructor or setter) to others classes managed by Spring. This add some configuration but remove a lot of bloat code. Spring is use a lot with Web application but fits perfectly if it's not web too.
0

I would try some approach like this:

/*
 * First, have a class which whatever your constants have in common.
 */
public class StatusInfos {
    String id;

    /*
     * Then create a subclass for every different object:
     */
    public class IntStatusInfo extends StatusInfos {
        int value;

        public int getValue() {
            return value;
        }
    }

    public class DoubleStatusInfo extends StatusInfos {
        double value;

        public double getValue() {
            return value;
        }
    }

    /*
     * You can then define your constants like this:
     */
    public static final StatusInfos THING_1 = new StatusInfos().new IntStatusInfo() {
        {
            id = "id1";
            value = 1;
        }
    };

    public static final StatusInfos THING_2 = new StatusInfos().new DoubleStatusInfo() {
        {
            id = "id2";
            value = 1.2;
        }
    };
}

BTW, it will be easier if you make your IntStatusInfo, DoubleStatusInfo, … into own class files, not inner classes.

Edit: It looks like you are writing some kind of configuration. If so, did you take a look whether you can use Apache Commons Configuration?

Edit 2: As per your comment: So you want to be able to iterate over the fields to process them. I just always have that “redundant” code, because the code usually is not really redundant. All of the fields are a little bit different. Instead, I have a clear data model in my object then. I usually have a function to output-convert / save the object (see toMap() in the example) and a constructor to input-convert the object. I frequently have several of them (to map, json, Android intent extras, xml, …) and I always have them in the class that is to be serialized or deserialized.

public class PlayerStatus {
    private final Set<Capability> capabilities = new HashSet<Capability>();
    private double height = 1.7;
    private int life;
    private int points;
    // ... 26 more

    /** 
     * Explicit default constructor.
     */
    public PlayerStatus() {}

    /**
     *  Constructor to restore an object.
     */
    public PlayerStatus(Map<String, String> data) {
        life = Integer.valueOf(data.get("life"));
        points = Integer.valueOf(data.get("points"));
        height = Double.valueOf(data.get("height"));
        for (String capability : data.get("capabilities").split(","))
            capabilities.add(Capability.valueOf(capability));
        // ... 26 more
    }

    /**
     * Getters and setters, as needed.
     */
    public void addCapability(Capability capability) {
        capabilities.add(capability);
    }

    public void addPoints(int points) {
        this.points += points;
    }

    public double getHeight() {
        return height;
    }

    public double getLifePercent() {
        return (double) life / 100;
    }

    public int getPoints() {
        return points;
    }

    public boolean hasCapability(Capability capability) {
        return capabilities.contains(capability);
    }

    public void looseCapability(Capability capability) {
        capabilities.remove(capability);
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public void setLifePercent(double value) {
        life = (int) Math.round(100d * value);
    }

    /**
     * Function to output-convert the object.
     */
    public Map<String, String> toMap() {
        Map<String, String> result = new HashMap<String, String>((int) Math.ceil(30 / 0.75));
        result.put("life", Integer.toString(life));
        result.put("points", Integer.toString(points));
        result.put("height", Double.toString(height));
        StringBuilder capabilitiesStringBuilder = new StringBuilder(16 * capabilities.size());
        for (Capability capability : capabilities) {
            capabilitiesStringBuilder.append(capability.toString());
            capabilitiesStringBuilder.append(",");
        }
        result.put("capabilities", capabilitiesStringBuilder.toString());
        // ... 26 more
        return result;
    }
}
5
  • 1
    It's not really a config... I'm developing this for a game, and the class holds the player's status infos, for example, hp, ep, etc. Also, the link doesn't look like I could iterate over the objects, and without that, I'd need to write much redundant code. Your code is a good idea, but I can't iterate over the elements if I put them into a list, because StatusInfos would need to declare getValue() which couldn't return a specific type...
    – Namnodorel
    May 19, 2016 at 14:14
  • How about public class StatusInfo { string Id; Class type; Object value; } ?
    – Caleth
    May 19, 2016 at 14:34
  • @Caleth That's basically just what I did with the enum, except this time it's not an enum...
    – Namnodorel
    May 19, 2016 at 18:21
  • I see this can be useful, but not how I could use it in my case. For example, if I have multiple elements (properties of the player), let's say fireresistance, physical resistance etc. Each information has the properties (final booleans) how the informatiob should be displayed (in percentage or plain value). The resistance value may be changed, the displayproperties not.Additionaly to the resistances, I have an element containing the effects the player has (poisoned). I want to iterate over the elements, display the resistances and display the effects in a special way. Did I misunderstood you?
    – Namnodorel
    May 20, 2016 at 13:16
  • I would not put displaying properties into your data class, but keeping the information how to display the values in some view class. You can for example just have no setters for values that should not change. May 23, 2016 at 8:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.