Java 重构if语句,其中我必须初始化不同的对象

Java 重构if语句,其中我必须初始化不同的对象,java,if-statement,hashmap,Java,If Statement,Hashmap,我正在寻找处理这种方法的最聪明的方法 public boolean addAccount(String cf, AccountType type) { String iban = name + cf; if (bankAccounts.containsKey(iban)) return false; if (type.name().equals("CHECKINGACCOUNT")) { CheckingAccount cc = new CheckingA

我正在寻找处理这种方法的最聪明的方法

public boolean addAccount(String cf, AccountType type) {
    String iban = name + cf;
    if (bankAccounts.containsKey(iban)) return false;
    if (type.name().equals("CHECKINGACCOUNT")) {
        CheckingAccount cc = new CheckingAccount(cf, iban, 0);
        bankAccounts.put(iban, cc);
        return true;
    }
    if (type.name().equals("DEPOSIT")) {
        DepositAccount cd = new DepositAccount(cf, iban, 0);
        bankAccounts.put(iban, cd);
        return true;
    }
    if (type.name().equals("WEB")) {
        WebAccount cw = new WebAccount(cf, iban, 0);
        bankAccounts.put(iban, cw);
        return true;
    }
  return false;
}
AccountType
是包含(存款、网络、支票账户)的枚举;
bankAccounts
是一个HashMap,包含
iban
(键)和
检查帐户或存款帐户或网络帐户
CheckingAccounts
DepositAccount
WebAccount
是三个类,它们继承了名为
Account
的抽象类

我试图用HashMap替换
if
,该HashMap使用用户插入的字符串检查密钥(帐户类型),并实例化与HashMap中的密钥相关联的三个类中的一个。 问题是我无法创建字符串和帐户之间的对应关系,因为我需要实例化它(但我当时不知道cf)


有人能告诉我一些更好的方法来管理它吗?

我建议不要使用任何类型的映射,因为它只会增加复杂性和运行时成本。switch语句似乎最简单。 以下是一个例子:

public boolean addAccount(String cf, AccountType type) {
    String iban = name + cf;
    if (bankAccounts.containsKey(iban)) return false;
    Account account;
    switch(type) {
      case CHECKINGACCOUNT:
        account = new CheckingAccount(cf, iban, 0);
        break;
      case DEPOSIT:
        account = new DepositAccount(cf, iban, 0);
        break;
      case WEB:
        account = new WebAccount(cf, iban, 0);
        break;
      default:
         return false; 
   } 
   bankAccounts.put(iban, account);
   return true;
}
但是,如果您决定使用类型映射:

static Map<AccountType, Class> TYPE_MAP = new HashMap<>() 
{
   {AccountType.CHECKINGACCOUNT, CheckingAccount.class},
   {AccountType.DEPOSIT, DepositAccount.class},
   {AccountType.WEB, WebAccount.class}
};

public boolean addAccount(String cf, AccountType type) {
    String iban = name + cf;
    if (bankAccounts.containsKey(iban)) return false;
    if (!TYPE_MAP.containsKey(type)) return false;
    Class classType = TYPE_MAP.get(type);
    Account account = (Account)classType
      .getDeclaredConstructor(
        String.class,
        String.class,
        Integer.class)
      .newInstance(cf, iban, 0);
    bankAccounts.put(iban, account);
    return true;
}
静态映射类型\u Map=newhashmap()
{
{AccountType.CHECKINGACCOUNT,CHECKINGACCOUNT.class},
{AccountType.DEPOSIT,DepositAccount.class},
{AccountType.WEB,WebAccount.class}
};
公共布尔addAccount(字符串cf,AccountType){
字符串iban=name+cf;
if(bankAccounts.containsKey(iban))返回false;
如果(!TYPE_MAP.containsKey(TYPE))返回false;
Class classType=TYPE\u MAP.get(TYPE);
Account=(Account)类类型
.getDeclaredConstructor(
String.class,
String.class,
整数(类)
.newInstance(cf,iban,0);
银行账户。put(iban,账户);
返回true;
}

为什么不使用工厂模式将要为哪个帐户创建的逻辑放在枚举本身中?自Java 8以来,此模式非常灵活,因为您可以将构造函数作为工厂的实现传入:

public boolean addAccount(String cf, AccountType type) {
    String iban = name + cf;
    if (bankAccounts.containsKey(iban)) return false;
    Account account = type.createAccount(cf, iban, 0);    
    bankAccounts.put(iban, account);
    return true;
}

public enum AccountType {
    CHECKING(CheckingAccount::new),
    DEPOSIT(DepositAccount::new),
    WEB(WebAccount::new);

    private final AccountFactory factory;
    AccountType(AccountFactory factory) {
        this.factory = factory;
    }

    public Account createAccount(String cf, String iban, int x) {
        return factory.create(cf, iban, x);
    }
}

public interface AccountFactory {
    Account create(String cf, String iban, int x);
}

与switch或map方法相比,这个解决方案有一个巨大的优势:如果您添加了一个新的子类和一个新的帐户类型,您就不会忘记处理这个新类型。其他解决方案将在运行时(而不是编译时)失败或给出错误的结果。

我的观点是,从概念上讲,使用这种方法一切都很好。不过,我会稍微改变一下:

   public boolean addAccount(String cf, AccountType type) {
    String iban = name + cf;
    if (bankAccounts.containsKey(iban)) return false;

    Account ac;
    if (type == CHECKING) {
        ac = new CheckingAccount(cf, iban, 0);
    } else if (type == DEPOSIT) {
        ac = new DepositAccount(cf, iban, 0);
    } else if (type == WEB) {
        ac = new WebAccount(cf, iban, 0);
    }
    bankAccounts.put(iban, cc);
    return true;
}

我不认为有任何理由让使用反射或工厂来创建帐户实例变得更复杂。它不会给你带来任何好处,你只会得到更多的代码,新人会花更多的时间来理解它。

我建议对类也使用泛型,
classs丑陋和低效的不是使用映射(顺便说一句,它应该是EnumMap)。丑陋的是反射的使用。如果在映射中存储工厂而不是存储类,则不需要反射。CHECKING(CheckingAccount::new)这里的CheckingAccount应该是CheckingAccountFactory吗?@IvanLymar No-
CheckingAccount::new
CheckingAccount
构造函数的一个参数。所有类都扩展了一个公共基类
Account
——因此工厂只是一个
AccountFactory
,有一个方法,它与每个扩展的构造函数具有相同的签名。@请参见您应该提到的,依我看,与switch或map方法相比,这个解决方案有一个巨大的优势:如果您添加了一个新的子类和一个新的帐户类型,您就不会忘记处理这个新类型。其他解决方案将在运行时失败,或给出不正确的结果