【问题标题】:Best practice for storing type of object in a class在类中存储对象类型的最佳实践
【发布时间】:2016-08-24 17:20:18
【问题描述】:

我有两种类型的交易: - 收入 - 费用

class Transaction {
    final public static int IN = 0x1, OUT = 0x2;
    final private int type;

    Transaction(int type)
    {
        this.type = type;
    }

    public int getType() {
        return type;
    }

    // --- internal logic is same for both types ---
}

// create:
Transaction t = new Transaction(Transaction.IN);

这种情况的最佳做法是什么?我应该声明一个枚举?两个班?我应该使用工厂模式吗?

【问题讨论】:

  • 最佳实践是两个类:可能是InTransactionOutTransactionIncomeTransactionExpenseTransaction。如果有用的话,两者都可以扩展Transaction
  • 交易中还有什么?类型只是以后分类的标记,还是会驱动 Transaction 方法的行为差异?如果它只是一条数据,你得到的很好,但如果不同的 Transactions 会有不同的行为,你最好创建不同的类。
  • 它只是一个标记,它被视图模块使用。两者的事务内部逻辑相同。
  • 为此目的声明一个枚举。
  • System.out 不同,这是有两个类的一个很好的理由,你不需要开关(这是一种强烈的设计味道)。

标签: java enums constants


【解决方案1】:

我建议在这种情况下使用Enumeration,因为这样,您可以以静态检查的方式限制可能的值:

enum TransactionType {
    Income, Expense;
}

class Transaction {
    final private TransactionType type;

    Transaction(TransactionType type) {
        this.type = type;
    }

    public TransactionType getType() {
        return type;
    }

}

否则,任何int 值都可以提供给您的构造函数Transaction(int type)

enums 的另一个好处是,您以后可以根据需要向他们提供一些附加信息(例如,不同的格式模式等)。

【讨论】:

    【解决方案2】:

    这实际上取决于您认为最简单的方法。枚举的优点是您可以将其设置为任何枚举并传输实例并从 itEnum 示例中获取值:

    private enum ENUM{
        EX1, EX2
    };
    

    然后这样称呼它:

    private ENUM instance = ENUM.EX1;
    

    如果你想检索值:

    switch(instance){
    
    case ENUM.EX1:
    
        break;
    case ENUM.EX2:
    
        break;
    
    }
    

    这是枚举示例:

    enum Transaction { 
    
        IN(0x1), OUT(0x2); 
    
        private int marker; 
        Transaction(int marker) { 
        this.marker = marker; 
        } 
    
    }
    

    枚举更容易,是的。

    比较:

    代码不一样,调用也不一样。但不多。

    主要区别在于您如何比较值。您必须在 switch 循环中实际获取实例的值(instance.getType())。

    两者都一样好,但在大多数情况下,我更喜欢枚举,因为它可以让我不必创建另一个类,因为我只需要一个枚举。虽然其他时候,枚举只是不削减它。在您的情况下,您似乎不能使用枚举(除非您将代码更改为“可接受的枚举”)。

    这种情况的最佳做法是什么?我应该声明一个枚举?

    在这种情况下?也许。这真的取决于你。然而,枚举是最简单的存储方式。

    【讨论】:

    • 你可以有一个与枚举相关联的数字代码(通过序数或在构造函数的帮助下有一个字段。
    • 你能用简单一点的英语解释一下吗?
    • 一个枚举被支持用于他们的目的。如果常量的指定序数值与您喜欢的不同,您仍然可以提供构造函数并执行IN(1),它可以映射到枚举中的变量;怀疑在这种情况下是否需要它。枚举还有其他优点,例如能够提供方法和类型安全。
    • IN(0x1) 仍然会导致未知令牌。我对枚举了解不多,因为除了字符串之外我并没有真正使用它,但我总是需要学习以备不时之需
    • 如果您只愿意将 Java 枚举用于最简单的场景,那么您将错过它们的巨大优势。构造函数不会使客户端变得更复杂。请阅读this
    【解决方案3】:

    最佳实践确实取决于用例。鉴于您在 cmets 中添加的内容,enum 似乎是更好的选择。 enum 可以封装“标记”的附加信息。例如,您说您使用基于交易类型的颜色进行打印。为避免执行额外的条件逻辑,您可以将该信息添加到 enum 值本身。例如:

    enum TransactionType {
        IN(Color.GREEN), OUT(Color.RED);
    
        public final Color TEXT_COLOR;
    
        TransactionType(Color textColor) {
            TEXT_COLOR = textColor;
        }
    }
    

    它还通过编译时检查提供更安全的使用。您可以通过让编译器检查正确的TransactionTypes 来使您的代码更加防伪。虽然它不是完全防伪的,因为你仍然可以做TransactionType.valueOf("DUMMY"),但它比在任何你可能需要使用标记的地方检查所有可能的错误要好。

    例如,您说需要查找给定类型的交易。你可以这样做:

    List<Transaction> ins = transactions.stream()
        .filter(t -> t.getType() == TransactionType.IN).collect(Collectors.toList());
    

    如果您的课程依赖于 int 值,则可以在其中抛出 42

    List<Transaction> ins = transactions.stream()
        .filter(t -> t.getType() == 42).collect(Collectors.toList());
    

    最糟糕的是它只会返回一个空列表;没有编译或运行时错误让您需要在某处验证值。

    另外需要注意的是,如果它真的只是一个标记,您可以将 Transaction 类完全替换为 enum,但需要更多信息来确定这一点。

    【讨论】:

      【解决方案4】:

      这真的取决于上下文,但如果你有:

      public class Transaction {
          private double amount = 0.0d;
          public static Transaction newExpenseTx() {
              return new ExpenseTransaction();
          }
          public static Transaction newIncomeTx() {
              return new IncomeTransaction();
          }
          public void setAmount(double a) { amount = a; }
          public double getAmount() { return amount; }
          public abstract Color getColor();
      
          static class ExpenseTransaction extends Transaction {
              Color getColor() { return Color.RED; }
          }
      
          static class IncomeTransaction extends Transaction {
              Color getColor() { return Color.GREEN; }
          }
      }
      

      你可以看到你的调用者不需要知道子类,你也不需要任何开关。

      Transaction t1 = Transaction.newExpenseTx();
      assertEquals("Exprense Transactions need to be red, has amount " +
                                                        t1.getAmount(),
                                                   Color.RED, t1.getColor());
      

      当然,如果您需要将类型作为值,添加 TransactionType 枚举并没有什么坏处。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-02
        • 1970-01-01
        • 2013-10-23
        相关资源
        最近更新 更多