避免在Java中使用具有附加字段的子类的instanceof

时间:2018-01-27 03:04:25

标签: java oop

我最近正在开发一个代码库,它在整个代码中使用了大量的instanceof检查,我想知道是否有更好的方法来重构它。

作为一个例子,有一个AbstractTender类,它有几个子类,CreditDebitTender,CheckTender,GiftCardTender,StoreCreditTender等。这些类中的每一个都添加了几个字段,方法和它自己的逻辑。这导致对代码进行检查,如下所示。

有没有更好的方法来避免代码库中的所有实例检查,因为在某些情况下,超类和子类IE之间存在显着差异,有很多非常不同的字段/方法?正如示例maskedCardNumber和authCode仅特定于信用借记投标,而micr仅针对检查投标。

if (tender instanceof CreditDebitTenderIfc) {
    // insert tender into credit debit tender table
}

if (tender instanceof CheckTenderIfc) {
    // insert tender into check tender table
}

if (tender instance of GiftCardTenderIfc) {
    // inser tender into gift card tender table
}

// etc

仅供参考:这是一个非常古老的代码库,原始产品已超过10年。

2 个答案:

答案 0 :(得分:1)

我可以通过两种方式思考:

  1. 在名为AbstractTender的{​​{1}}中定义一个抽象方法。每个子类都必须实现信息应该如何存储在数据库中。

  2. 如果save和子类是实体类而不能拥有存储库逻辑,并且如果使用Java 8,则可以使用AbstractTender,其中地图的每个值都关注如何存储Map<Class, Consumer<AbstractTender>>的实例。您可以使用实例的类来查找特定元素。

    简要示例:

    AbstractTender

    然后您的Map<Class, Consumer<AbstractTender>> mapTenderStoreFunc = new HashMap<>(); mapTenderStoreFunc.put(CreditDebitTenderIfc.class, tender -> { CreditDebitTenderIfc cdTender = (CreditDebitTenderIfc)tender; //logic goes here... }); mapTenderStoreFunc.put(CheckTenderIfc.class, tender -> { CheckTenderIfccdTender ctifc = (CheckTenderIfc)tender; //logic goes here... }); //and on... 方法会像这样使用地图:

    save

    这种方法的缺点是,如果团队中的某个人忘记为子类添加正确的映射,那么您就会陷入困境。

  3. 2的类似方法,但是如果您使用Java 7或更早版本,而不是public void save(AbstractTender tender) { Consumer<AbstractTender> saveOperation = mapTenderStoreFunc.get(tender.getClass()); if (saveOperation != null) { saveOperation.accept(tender); } else { //maybe throw an exception //or log a warning, error or something to notice! } } ,您可以定义自己的界面并用匿名类填充它:

    Consumer<AbstractTender>

答案 1 :(得分:1)

根据代码确定已经创建了招标对象。 该对象可以是任何一个子类对象。 所以可以使用回调行为。

public abstract class AbstractTender{

abstract void insert();

}

public class CreditDebitTenderIfc extends AbstractTender{
@Override
public void insert(){
  // insert tender into credit debit tender table
}
}

class Main{

public void doOperation(AbstractTender tender){
       tender.insert();
}

}

由于你已经有了招标对象,只需打电话 tender.insert(); 它将调用适当的子类方法。