简体   繁体   中英

What type of variable is most appropriate for this task?

I am currently creating a class for a small project and ran into an interesting scenario that I haven't really dealt with before.

My program will just display information about certain items in a game. The category I'm having issues with is the costs of the item. For instance, the item cost can be:

  • 100 Silver and 300 Stone
  • 500 Copper, 300 Stone, and 2 Rare Metal
  • 175 Gold

The cost could be any of those, meaning it could only cost one type of 'currency' or could cost up to three different kinds of 'currency'. Also, each type of currency would contain a picture of it. So 100 Silver and 300 Stone would look something like: 100(Int) Silver(image) and 300(Int) Stone(Image)

So seeing as there could be multiple types of currency and images, would one store it in an array? Or another type of variable?

Just looking for someone to shed light on the issue. If it needs to be explained with a sample of the class, I can do so.

EDIT

Although my explanation lacked clarity, I received many good responses. In fact, quite a few are suitable to be the correct answer. I appreciate all the responses and have upvoted each of you who had helpful feedback.

Thank you everyone!!!

You can create a very simple class Cost

public class Cost {
    int amount;
    String currency;

    public Cost(int amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }
}

and then implement the cost as an ArrayList

List<Cost> cost = new ArrayList<Cost>();
cost.add (new Cost(100, "Gold"));

This is simple enough while retaining flexibility to add new currencies


An example with an enum:

public class Cost {
    private int amount;
    private Currency currency;

    public Cost(int amount, Currency currency) {
        this.amount = amount;
        this.currency = currency;
    }
    public enum Currency {
        GOLD { public String toString() { return "gold"; } },
        SILVER { public String toString() { return "silver"; } },
        COPPER { public String toString() { return "copper"; } },
        STONE { public String toString() { return "stone"; } },
        RARE_METAL { public String toString() { return "rare"; } }
    }

    public String getImageName() {
        return new String(currency.toString()+".png");
    }

    public int getAmount() {
    return amount;
    }

    public String getCurrency() {
        return currency.toString();
    }
}

List<Cost> costs = new ArrayList<Cost>();
cost.add (new Cost(100, Cost.Currency.GOLD));
cost.add (new Cost(200, Cost.Currency.COPPER));

for (Cost cost: costs) {
    ImageIcon icon = createImageIcon(cost(i).getImageName());
    JLabel label1 = new JLabel(cost(i).getAmount(), icon, JLabel.CENTER);
}

Java's an object-oriented language; why not have an Item or Commodity class that encapsulates the behavior that you want instead of relying on primitives? You'll hide complexity from clients by encapsulating it into the class.

If you have several Currency instances, you can also encapsulate conversions between them rather than embed constants all over your code. If you change conversions, you'll only have to do it in one place.

Also, and this is important so I'm putting it at the top, even though it's an edit. Don't include pictures in anything with this You should only have pictures on the user interface. In theory, you could run the game from a command prompt just typing your commands. "Buy sword" "sell junk" "attack goblin" etc. When you start incorporating your UI and "business logic" you find yourself having a very difficult time separating the two when it comes time to fix stuff.

I would have something like this

class Cost {
    // use the builder pattern - it makes it VERY easy to add new currency types
    // without breaking existing types
    // it does make it more difficult to remove types, but you would have to
    // modify everywhere a type that used a removed currency anyway, so it's no
    // ADDITIONAL work there.
    class Builder {
        private int copper;
        private int silver;
        private int gold;

        public Builder copper(int cu) { this.copper = cu; return this; }
        public Builder silver(int ag) { this.silver = ag; return this; }
        public Builder gold(int au) { this.gold = au; return this; }

        public Cost complete() {
            return new Cost(this);
        }

    }
    public final int copper;
    public final int silver;
    public final int gold;
    // other costs;

    private Cost(CostBuilder cb) {
        this.copper = cb.copper;
        this.silver = cb.silver;
        this.gold = cb.gold;
    }

}

class Item {
    String name;
    // other stuff

    private Set<Cost> costs;

    public Set<Cost> getCosts() {
        return java.util.Collections.unmodifiableSet(costs);
    }
}

use the code like this:

Cost allGold = new Cost.Builder().gold(175).complete();
Cost goldAndSilver = new Cost.Builder().silver(50).gold(50).complete();
Cost allMaterials = new Cost.Builder().gold(10).silver(30).copper(100).complete();

Set<Cost> costs = new HashSet<Cost>();
costs.add(allGold);
costs.add(goldAndsilver);
costs.add(allMaterials);

Item swordOf1000Truths = new Item("Sword of 1000 truths",costs);

and later you can do this

// assume player found allGold by quering for what costs he could use
if(player.canAfford(allGold)) {
    player.spend(allGold);
    player.addItem(swordOf1000Truths);
}

In the code I would just store the cost of the item as a single value (int or double). Then when you display the cost have some class that translates the internal value into whatever currency you want to show.

No need to carry around an array of values if all the values are essentially the same.

No built in type of variable is appropriate, so you need to make Classes that represent your concepts. At least Cost should be a class and maybe also currency, but an Enum might do for that.

I would probably go for an enum to represent the various types of currencies. Something like this:

public enum Currency {
    GOLD("gold"),
    SILVER("silver"),
    COPPER("copper"),
    STONE("stone");

    private String displayName;

    private Currency(String displayName) {
        this.displayName = displayName;
    }

    public String toString() {
        return displayName;
    }
}

Here the enum actually has a field to store a user-friendly display name for the currency; this isn't necessary--I just threw it in to make the output pretty later on in my example. It could also store a corresponding image filename (or even an actual image) but that might be better left up to whatever UI you're using rather than putting it in the model here.

Your item needs just one Map to store its costs:

private Map<Currency, Integer> costs;

A rough example of how to use it:

Item vorpalSword = new Item();
vorpalSword.getCosts().put(Currency.GOLD, 100);
vorpalSword.getCosts().put(Currency.STONE, 300);

StringBuilder costOutput = new StringBuilder();
for(Map.Entry<Currency, Integer> cost : vorpalSword.getCosts().entrySet()) {
    costOutput.append(cost.getValue() + " " + cost.getKey() + " ");
}
System.out.println(costOutput.toString());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM