使用静态类来表示不同形式的货币

时间:2016-05-28 00:24:41

标签: java static

我在开发一款小游戏时,昨晚给自己编了一个问题。前几天,我确信自己应该将我的一些业余时间用于高效工作,所以我决定开始研究基于文本的RPG,而不是游戏。那么,我来到游戏中代表货币的问题。现在,因为这只是为了好玩,我想稍微挑战自己。而不是仅仅将货币表示为单一价值(例如:称为&#34的单一类型的硬币;金币和#34;不是游戏中唯一的硬币。)

我决定做的是创造4种类型的硬币 - 便士,铜,denar和oren。所有4个硬币都具有重量,体积,材料和名称等值。此外,硬币具有汇率,这决定了它们的相对价值。这样做的目的是允许不同的用法,否则将是一种无聊的旧货币。我的问题是我不确定如何实现它。

昨晚我到达的是4班(Pence,Copper,Denar,Oren),他们扩展了一个抽象级的硬币。硬币包含许多受保护的静态元素,例如所有4个子类的DENSITY,VOLUME,NAME,EXCHANGE。

子类的构造函数如下所示:

public Coppers() {
    super();
    super.metal = COPPER_METAL;
    super.name = COPPER;
    super.setVolume();
    super.setDensity();
    super.setWeight();
}

超类中的方法如下所示:

protected void setDensity() {
    switch( getMetal()) {   
    case "copper":
        this.density = DENSITY_COPPER;
        break;
    case "silver":
        this.density = DENSITY_SILVER;
        break;
    case "gold":
        this.density = DENSITY_GOLD;
        break;
    default:
        this.density = DENSITY_COPPER;
        break;
    };
}

这似乎非常......错了。我不确定最佳做法是什么。我问我的朋友们使用静态类来保存这些值,并收到混合响应。但这些类的POINT很重要。想象一下,玩家类有一个名为Purse的对象,它跟踪不同类型硬币的数量。通过他们的钱包,玩家可以在银行兑换硬币,购买商品和出售硬币。持有一套所有实例化硬币是没有任何意义的,对吧?我只需要信息和方法。那么实现静态类是否有意义?当他们共享这么多属性时,我如何才能让所有4个硬币最佳?

4 个答案:

答案 0 :(得分:1)

在这种情况下,您可以使用Enum。你枚举了你需要的常量,通过它们的构造函数给它们一个类型。

现在我们有他们的类型,我们可以将它与您在代码中处理的字符串进行比较,如果没有类型匹配,我们默认将其设置为Density.COPPER

Density density;

protected void setDensity (String metal) {
    for (Density d : Density.values()) {
        if (metal.equals(d.getType())) {
            this.density = d;
            return;
        }
    }
    this.density = Density.COPPER;
}

enum Density {
    COPPER("copper"),
    SILVER("silver"),
    GOLD("gold");

    String type;

    Density(String s) {
        type = s;
    }

    public String getType() {
        return type;
    }
}

答案 1 :(得分:1)

让我们在这里倒退。

  

想象一下,玩家类有一个名为Purse的对象,它跟踪不同类型硬币的数量。通过他们的钱包,玩家可以在银行兑换硬币,购买商品,并出售硬币货物。

这意味着什么:

public class Purse {
    private final List<Coin> coins = new ArrayList<>();
}

这告诉我这里的枚举不够(足够)。此上下文中的枚举描述了多个状态;您正在寻找的是实际对象,它们可以保存您需要进行某些计算的值。

如果我们打算坚持这种货币,我认为某些中心对象没有任何问题来描述它。

在我看来,使用抽象类可能没问题,但你错过了一个关键组件:一个工厂来创建你想要的硬币类型。你也想完全减少硬币的责任 - 硬币知道它的价值是好的,但它不应该关心它相对于其他硬币的价值;这是某种交换对象的责任,它打算根据你给定硬币的价值产生一些硬币。

所以让我们编写抽象类的构造函数。如果我们想要创建一个通用硬币,我们需要知道它的体积,密度和重量。这个名字是根据它的类名提供的,所以你真的不必担心这个;你可以在以后提取它。

如果您想要某种硬币层次结构,可以使用Comparable;说明那里的排序,而不是通过枚举。

public abstract class Coin implements Comparable<Coin> {

    protected final int volume;
    protected final int density;
    protected final int weight;

    public Coin(int volume, int density, int weight) {
        this.volume = volume;
        this.density = density;
        this.weight = weight;
    }

    public int getVolume() {
        return volume;
    }

    public int getDensity() {
        return density;
    }

    public int getWeight() {
        return weight;
    }
}

这描述了准系统Coin类型。

例如,我们也在这里描述Copper类型。该代码假设相同类型的硬币具有可比性,否则它会自行降级(铜位于列表的底部)。

观察一些事情:

  • 我们保留了很多来自父类的原始逻辑
  • 我们覆盖compareTo(因为我们必须),我们让那个驱动器成为硬币订购的主要方式。
  • 描述任何类型的转换,因为硬币真的不需要知道。它们在硬币之间没有任何价值,直到实际转换它们为止。想想foreign exchange.
public class Copper extends Coin {

    public Copper(final int volume, final int density, final int weight) {
        super(volume, density, weight);
    }

    @Override
    public int compareTo(final Coin otherCoin) {
        if(otherCoin instanceof Copper) {
            return (volume - getVolume()) + (density - getDensity()) + (weight - getWeight());
        }
        // assume Coppers are worth the least
        return Integer.MIN_VALUE;
    }
}

其他货币留给读者练习。

我想要涵盖的最后一件事是适用于所有货币的某种形式的发电机。这是一些反射魔法可以真正帮助调用你关心的构造函数。

我还将此返回Optional<T extends Coin>,以便在生成失败的情况下出于某种原因,您可以选择使用而不是null

public class CoinFactory {

    private CoinFactory() {

    }

    public static <T extends Coin> Optional<T> generateCoin(int weight, int volume, int density, Class<T> clazz) {
        Optional<T> coin = Optional.empty();
        try {
            coin = Optional.of(clazz.getDeclaredConstructor(int.class, int.class, int.class)
                 .newInstance(weight, volume, density));
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return coin;
    }

}

您可以使用此main方法对其进行抽烟测试:

public static void main(String[] args) {

    final Optional<Copper> x = CoinFactory.generateCoin(10, 20, 30, Copper.class);
    if(x.isPresent()) {
        System.out.println(x.get());
    }
}

答案 2 :(得分:0)

Map中为密度设置私有Coin,密钥为“铜”,“金”和“银”,值为DENSITY_常量。 setDensity()应该只运行:

this.density = densityMap.get(getMetal());

或者更好的是,废弃setDensity(),而只是getDensity(),返回densityMap.get(getMetal())

答案 3 :(得分:0)

由于四种硬币的行为没有区别,一个类就足够了。我建议这个:

public enum Coin {
  PENCE, COPPER, DENAR, OREN;

  private static final String[] METAL = { "copper", "copper", "silver", "gold" };
  private static final int[] VALUE = { 1, 12, 60, 360 };

  public String getMetal() {
    return METAL[ordinal()];
  }

  public int getValue() {
    return VALUE[ordinal()];
  }
}