tags:

views:

96

answers:

5

Hi, I have an abstract class called account which is as follows -

abstract class Account
{
    private int number;
    private String owner;

    public Account(int accountNumber, String  accountOwner)
    {
        number = accountNumber;
        owner = accountOwner;
    }

    public int getAccountNumber(){ return number; }
    public String getAccountOwner(){ return owner; }
    public abstract double getBalance();
    public abstract double  makeDeposit(double  amount);
    public abstract double  makeWithdrawal(double  amount);
}

This class defines the basic skeleton for an account. Several specialized account class will be created by inheriting this class, such as MarketSavingsAccount, RegularSavingsAccount etc.

Now I have an array which is declared as follows -

Account[] accounts

which contains a list of accounts. In this array different types of accounts are available. Now how can I determine which of these array members is an instance of MarketSavingsAccount?

+2  A: 
accounts[0] instanceof MarketSavingsClass

or dynamic version

MarketSavingsClass.class.isInstance(accounts[0])

More on the topic (scroll down to "The Type Comparison Operator instanceof")

Nikita Rybak
+3  A: 

You can loop through the array and use the instanceof operator to find out if the current element is an instance of MarketSavingsClass.

Something like this (not tested):

for (Account anAccount : accounts) {
    boolean isInstance = anAccount instanceof MarketSavingsClass;
}

That said you need to look at your design again. You shouldn't have to type check except in very rare cases.

Manoj Govindan
+1 : Nice ! [15 char]
Chankey Pathak
+5  A: 

From a pure OOP standpoint you're not supposed to care; you're supposed to avoid downcasting and treat all the Account instances the same.

But enough theory - you're probably looking for instanceof, as in

Account a = accounts[0];
if (a instanceof MarketSavingsAccount)
{
    ...
}
jwismar
Edit : ....probably looking for in[s]tanceof, as in...
Chankey Pathak
@Chankey: right you are. Fixed. Thanks!
jwismar
@jwismar: So what could be the work-around to avoid this kind of design flaws?
Night Shade
@jwismar : Welcome :)
Chankey Pathak
+1  A: 

Consider a Factory design pattern. It's made for the task.

  • Create an interface called Account that defines all the methods that accounts need.

  • Create a Factory class, something like this:

public class AccountFactory {
   public static Account make([arguments]) {
      Account specificInstance = null;
      // Do whatever logic is necessary to determine the type of account you need.
      return specificInstance;
   }
}

You have to give make() enough information to decide which type of Account implementation is appropriate.

  • Create your MarketSavingAccount, RegularSavingsAccount, etc that all implement Account.

  • Let AccountFactory.make() determine the right Account implementation to use and return to you an instance.

Your code mainline code shouldn't care one bit what type of account is being processed.

Tony Ennis
+1  A: 

Rather than use instanceof, which is not very object-oriented for reasons already mentioned---specifically, you should use polymorphism in an object-oriented design, you can specify the account type in your Account class and check it without using instanceof but instead getAccountType().

abstract class Account
{
    public enum Type { MARKET_SAVING, REGULAR_SAVING, CHECKING };

    private final Type type;
    private int number;
    private String owner;

    public Account(Type accountType, int accountNumber, String accountOwner)
    {
        type = accountType;
        number = accountNumber;
        owner = accountOwner;
    }

    public Type getAccountType(){ return type; }
    ...
}

The subclasses must be required to specify a Type, and the compiler will enforce this if all Account constructors have a Type parameter. With instanceof, there is no compile-time check that all subclasses of Account are handled. You'll have to make sure that the code handles all of the enum values, but that is often a more constrained problem than trying to know and handle all subclasses of Account because the Type enum is specified as part of the Account data type.

Now if there is some behavior that is supposed to be different for each account, that behavior should be handled, polymorphically, within or at least through the subclasses of Account rather than through code that checks the type and performs specific operations, but if you just want to find the accounts of a particular type, having the type be a property of the Account objects will allow you to avoid depending on knowing the classes that implement each particular account type.

public class MarketSavingsAccount extends Account
{
    MarketSavingsAccount(int accountNumber, String accountOwner)
    {
        super(Type.MARKET_SAVING, accountNumber, accountOwner);
    }
    ...
}

Maybe there's some other implementation of MarketSavingsAccount that needs to be treated as a market savings type of account:

public class OtherMarketSavingsAccount extends Account
{
    OtherMarketSavingsAccount(int accountNumber, String accountOwner)
    {
        super(Type.MARKET_SAVING, accountNumber, accountOwner);
    }
    ...
}

If you have code that just want to find the market saving accounts, you would just iterate over the array and act on those of Type.MARKET_SAVING, which includes both MarketSavingsAccount and OtherMarketSavingsAccount as well as any other implementations that you may have.

for (Account account : accounts) {
    if (account.getAccountType() == Type.MARKET_SAVING) {
        addToDirectMailAccountsList(account); // Or whatever
    }
}
Fly
This type of do-it-yourself type identification isn't really a good idea. 1) It's not any better from an OO theoretical standpoint -- you're still checking the dynamic type of the class, which is frowned upon. 2) It's not likely to be faster -- the language almost certainly already has the information available to it, and your storing an additional copy isn't any better. 3) Why reinvent the wheel? Lots of best-practices involve utilizing what the language and libraries provide for us, so that we don't have to re-create it.
jwismar
Rather than checking the dynamic type of the class, it's checking a real property of the Account data type while instanceof is checking the implementation. It's not so much reinventing the while as simply having an appropriate property of the data type. I think the "account type" is an appropriate property of an account data type. For example, the account type is something that would be printed on an account statement, but the actual class name is certainly not.
Fly
It's still a bad idea to check the account type to control behavior as noted because one should use polymorphism.
Fly