ABHISHEK KUMAR
ABHISHEK KUMAR

Reputation: 71

How to select a base class at runtime depending upon an instance variable of parent class in Java?

Problem: With the following classes, I am trying to select a base class at runtime depending upon an instance variable of parent class in Java. I believe there should be some fundamental property in OOPS which can help me achieve it which I am just missing.

    class Transaction{
       int id;
       enum transactionType;
    }

    class ATypeTransaction extends Transaction{
       /* bunch of instance variable specific to ATypeTransaction */
    }

    class BTypeTransaction extends Transaction{
       /* bunch of instance variable specific to BTypeTransaction */
    }
 /* The event can be triggered with any transactionType as declared in the enum TransactionType as each event would be associated with one transaction.*/
        class Event{
           int eventId;
           enum transactionType;
        }

Based on the transactionType, I have to prepare Transaction Payload and attributes will be different for different base classes as shown below.

My Approach: I am trying to use something like this (static polymorphism within switch-case) in an attempt to resolve the Transaction instance based on the transactionType.The problem with this approach is I am still not able to get hold of the child class. Rather I am getting parent class which stops me from accessing child class attributes.

public Transaction selectTransaction(TransactionType transactionType){
        Transaction transaction;
        switch(transactionType) {
            case = "AType":
                transaction= new ATypeTransaction();
                break;
            case = "BType":
                transaction= new BTypeTransaction();
                break;
        }
   return transaction;
}

Please help me out with this problem and provide a good design to solve this. Thanks in advance.

Upvotes: 0

Views: 635

Answers (4)

Konrad Botor
Konrad Botor

Reputation: 5063

If you're set on selecting type of returned object using switch and enum type I think this will be the best solution:

public static enum TransactionType {
    AType,
    BType
}

public static class Transaction {
    public static void main(String[] args) {
        ATypeTransaction transA = selectTransaction(TransactionType.AType);
        BTypeTransaction transB = selectTransaction(TransactionType.BType);
        Transaction trans = selectTransaction(TransactionType.AType);

        transA.doA();
        transB.doB();
        ((ATypeTransaction)trans).doA();

        //The following will cause class cast exception
        ATypeTransaction transC = selectTransaction(TransactionType.BType);
        ((BTypeTransaction)trans).doB();
    }

    @SuppressWarnings("Unchecked")
    public static <T extends Transaction> T selectTransaction(TransactionType transactionType){
        switch(transactionType) {
            case AType:
                return (T) new ATypeTransaction();
                break;
            case BType:
                return (T) new BTypeTransaction();
                break;
        }
    }
}

public static class ATypeTransaction extends Transaction {
    public void doA() {}
}
public static class BTypeTransaction extends Transaction {
    public void doB() {}
}

Unfortunately, unless you know if the result of selectTransaction method will be a specific superclass of class Transaction (so you can save it to a variable of a correct type) or if you check the type using operator instanceof (in case of variable of class Transaction), you'll risk JVM throwing ClassCastException.

Upvotes: 1

Ralf Kleberhoff
Ralf Kleberhoff

Reputation: 7290

For some reason, you want your API to contain a method like Transaction selectTransaction(...).

This assumes that your callers won't care about the concrete implementation of Transaction, but can do everything they want just using methods from the Transaction type, never needing anything specific from ATypeTransaction or BTypeTransaction.

Your question shows that this isn't true, the callers seem to need access to specific elements (methods or even fields) of the individual types.

There are two possible roads:

  • Abandon the common parent class Transaction, and live with two independent classes ATypeTransaction and BTypeTransaction, or
  • Find the use cases where the subtypes are handled differently, create an abstraction (abstract method) in the parent class, and implement it individually in the subclasses.

Upvotes: 0

Simon Rechermann
Simon Rechermann

Reputation: 501

i think switch-cases in java only works with byte, short, char, string and enum. You could use the instance of Operator in an if statement. But maybe there are some better solutions when it comes to design patters.

Upvotes: 0

Marc Stroebel
Marc Stroebel

Reputation: 2357

put the business logic to your data:

class Transaction{
   int id;
   enum transactionType;

   public void handleTransaction() {
     //common code
   }
}

class ATypeTransaction extends Transaction{
   /* bunch of instance variable specific to ATypeTransaction */
   @Override       
   public void handleTransaction() {
     // access specific attributes
     super.handleTransaction();
   }
}

Upvotes: 0

Related Questions