开发者

Java inheritance problem : Determining appropriate subclass

开发者 https://www.devze.com 2023-01-16 21:40 出处:网络
I have an abstract class called account which is as follows - abstract class Account { private int number;

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 accou开发者_如何学Gont. 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?


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)
{
    ...
}


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.


accounts[0] instanceof MarketSavingsClass

or dynamic version

MarketSavingsClass.class.isInstance(accounts[0])

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


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.


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
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消