【问题标题】:Different Enum method parameters不同的枚举方法参数
【发布时间】:2013-05-14 13:35:20
【问题描述】:

我遇到了一个需要做出设计决策的案例(与其说是程序本身,不如说是为了了解其他人在这种情况下做了什么,最好把它看作是是一个 API)。我有一个枚举类:

public enum Type
{

    CAPTAIN(2),  // Only Use CalcMorale never other
    LEADER(5),   // Only use CalcMorale never other
    PARTIER(80); // Only use CalcMorale2 never other

    int calcMorale(int inMorale)
    {
        return inMorale * (100 + morale) / 100;
    }

    int calcMorale2(int inMorale, int teamCount)
    {
        return inMorale + morale * teamCount;
    }

    int morale;

    private Type(int aMor)
    {
        morale = aMor;
    }

}

有一个类 Character 持有这些枚举之一,也是传入参数的那个。

评论的问题是我只希望某些枚举使用枚举类中的某些方法。领导者增加了 5% 的团队士气,但党员为该党内的每个成员增加了 80%,因此需要另一个参数。我可以通过几种方式解决问题,但想知道社区对如何解决问题的普遍共识。

我可以:

让程序员有责任调用正确的方法。 (这对我来说听起来不对)。

给每个枚举它自己的函数版本。 (这会产生一个巨大的文件,我会重复很多代码)。

将责任留给“Character”类,该类有一个带有开关的方法来处理这个。 (这意味着程序员可以更改计算而不是故意的)。但是,如果我想稍后将枚举移动到文件中,这将导致更少的问题。但是我质疑这是否会破坏封装,如果这只是枚举的责任。

使类型成为一个类并通过匿名内部类定义方法。在这种情况下,类将添加到地图中,而不是在枚举类中使用 getByName()。

--

你认为什么最合适? (我更喜欢我的类尽可能地独立,就像我使用 API 一样(它不会),你的建议会如何/会根据枚举的数量受到影响?那我想要的情况呢?能够同时使用这两种方法的枚举?语言是 Java。

【问题讨论】:

  • 它们是不同的野兽(不同的方法签名),所以你不应该试图把它们塞进一个类中。
  • @Bohemian 好吧,通过将它们分开,我不能在字符类中拥有一个“类型”成员。但相反,必须采用一种根本不受欢迎的继承类型结构。您也同意 hoaz 的方法是正确的解决方案,那不是也将它们挤在一起吗?

标签: java enums


【解决方案1】:

正如您所说,您必须考虑您的应用程序将如何处理此问题。如果您希望枚举类自己处理这个问题,您将需要某种条件和某种形式的重载(这意味着开发人员将负责调用正确的方法。

但是,您可以强制开发人员始终发送 teamcount:

public enum Type {
    CAPTAIN(2),
    LEADER(5),
    PARTIER(80);

    private final int morale;

    private Type(int m){
        morale = m;
    }

    public int getMorale(int inMorale) {
         return getMorale (inMorale, 0);
    }

    public int getMorale(int inMorale, int teamCount) {
        switch (this) {
            case CAPTAIN:       
            case LEADER:
                return inMorale * (100 + morale) / 100;
            case PARTIER:
                return inMorale + morale * teamCount;
        }
        return 0;
    }
}

编辑:将开关更改为“this”

【讨论】:

  • 这可能是迄今为止 IMO 最理想的解决方案,谢谢。但这又把调用正确方法的责任留给了程序员,这不是什么大问题,因为他们不能通过适当的检查来破坏任何东西。
  • +1 - 虽然我建议将开关从士气更改为this,并改为使用枚举类型(以防两个或更多士气匹配/更具可读性/更快)。
  • @RickTaemen 但是,当您调用 getMorale() 时,您需要指定 teamCount 当它是一个 PARTIER 以获得正确的数量。克服这个问题的简单方法是要求它,即使它不会被计算使用。
  • @Pescic 这似乎是合适的,不可能有一个完美的方法来完成我认为的所有事情(不会导致代码混乱)。没有声誉我不能 +1,但是 +1 :)
【解决方案2】:

您可以将多个参数传递和存储到 Enum 值:

public enum Type
{

    CAPTAIN(2, true),  // Only Use CalcMorale never other
    LEADER(5, true),   // Only use CalcMorale never other
    PARTIER(80, false); // Only use CalcMorale2 never other
    ...

    int morale;
    boolean useFirstMethod;

    ...

    int calcMorale(int inMorale, int teamCount)
    {
        if (useFirstMethod) {
            return inMorale * (100 + morale) / 100;
        } else {
            return inMorale + morale * teamCount;
        }
    }

    ...
}

【讨论】:

  • 您需要在 calcMorale() 中加入 teamCount - 我认为这是主要问题。
  • @hoaz 在这种情况下,teamCount 将是未定义的。不过还是谢谢你的回复。
  • 你说得对,我错过了那部分,我会添加第一个例程中没有使用的第二个参数,但我不再喜欢这个解决方案了
  • +1 这是正确的方法。但是这两个字段都应该是finalelse 是多余的 - 只需 if(X) return A; return B;
  • 另外,这不适用于两个以上版本的方法。
【解决方案3】:

让程序员有责任调用正确的方法。 (这 对我来说听起来不对)。

你是对的,这不是最佳解决方案。

给每个枚举它自己的函数版本。 (这将使 大文件,我会重复很多代码)

这听起来像是第一个选项的扩展:现在调用者负责整理 n 个方法中的哪一个来调用 n 个 enum 值。

考虑继承方法而不是enums:

calcMoralecalcMorale2方法很相似,可以在一个接口中组合:

public interface Type
{
    int calcMorale(int inMorale);
}

这个abstract 类可以定义你常用的calcMorale 功能(其他人会在必要时覆盖它)。

public abstract class AbstractType
{
    protected final int morale;

    public AbstractType(int morale)
    {
        this.morale = morale;
    }

    int calcMorale(int inMorale)
    {
        return inMorale * (100 + morale) / 100;
    }
}

CaptainLeader 直接从 AbstractType 扩展

public class Captain extends AbstractType
{
    public Captain()
    {
        super(2);
    }
}

public class Leader extends AbstractType
{
    public Leader()
    {
        super(5);
    }
}

但是Partier 覆盖了calcMorale 方法(第二个参数作为构造函数参数传递)

public class Partier extends AbstractType
{
    private final int teamCount;

    public Partier(int teamCount)
    {
        super(80);
        this.teamCount = teamCount;
    }

    @Override
    public int calcMorale(int inMorale)
    {
        return inMorale + morale * teamCount;
    }
}

【讨论】:

  • 感谢您的建议。然而,虽然这种方法会奏效。我担心随着扩展 AbstractType 所需的类数量越来越大(比如 1000 个),这将是一种非常繁琐的方法,并且会使文件大小变大,而每个类的变化很小。
  • @RickTaemen 您可以拥有一个包含所有逻辑的大型文件,或者您可以将您的逻辑分成小块,易于理解的块。如果你真的要使用 1000 种不同的方法来计算士气,那么尝试保持大量的情况转换可能同样乏味。此外,每次您需要添加新类型时,您都必须编辑大量的 enum 类。另一方面,您可以添加一个新的class;使用您的代码的其他人可能无法编辑 enum
  • 这确实是一个有效的观点,尤其是关于无法访问/编辑枚举的部分。虽然这是一个足够小的项目并且根本不会有太多混乱,但我肯定会在未来的大型项目中记住这一点,这可能是更好的解决方案。 +1 当我可以的时候。然而,由于我可以允许开关流经多个值,可能会减少多个类的开销,以及对该方法的更高共识,其他答案仍将被接受。
猜你喜欢
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
相关资源
最近更新 更多