Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Inheritance and avoiding constant use of instanceof

I have three classes, an abstract User and two specific: NormalUser which holds an ArrayList of one or more Address objects which can be different (domestic, international, custom etc.) and then the Admin class which has a method which returns true . They both contain more methods which are unrelated to each other.

abstract class User{
    public User(String username, String pw){
 ...

}

public class NormalUser extends User{
...
    private ArrayList<Address> addresses;

...

    public void addAdress(ArrayList<Address> address){
        addresses.addAll(address);
}

public class Admin extends User{

...
    public boolean getIsAdmin(){
        return true;
  }
}

Now in another class if I make 4 user objects like this for example:

    ArrayList<User> users;

    users.add(new NormalUser( "1", "pw");
    users.add(new NormalUser( "2", "pw");
    users.add(new NormalUser( "3", "pw");
    users.add(new NormalUser( "4", "pw");
    users.add(new Admin("5", "pw"));
    users.add(new NormalUser( "6", "pw");

And say I want to use the addAddress method in NormalUser, then I have to downcast the specfic user in users to NormalUser, before I can use the addAddress method in NormalUser like this:

     if (user instanceof NormalUser){
        NormalUser normal = (NormalUser) user;
        normal.addAddress(...)
        }

The reason why I would like both NormalUser and Admin to be a User is so I can process them together when logging in.

I thought of adding the addEmail to the User class and then overriding it in the NormalUser class, but I would have to do that for every method in the NormalUser class, plus Admin would inherit it from the User as well, when it doesnt need that functionality.

Question 1: Is there a better way to do this as I heard using instanceof is a bad thing? and I would have to use instanceof every time I use a method that is specific to the NormalUser class.

Quesiton 2: Is an ArrayList of object Addresses the best way to link the RegularUser to specific addresses/(Objects)?

There is no database involved right now.

So for example user a has 2 addresses one domestic and one international, and user b just has a domestic address, user c has a domestic and a custom address etc.

Thanks.

PS. I've searched the previous posts extensively but havent found a solution. In both my Java books they both show examples of using instanceof but no mention of it being a bad practice.

like image 243
Brah Avatar asked Oct 24 '22 16:10

Brah


1 Answers

You can use the Visitor pattern - a bit clumsy and slightly unreadable, but probably the best solution for your problem.

Actually your solution with pushing addEmail to base class isn't that bad. Simply provide an empty implementation in base User and override in RegularUser. If you want to check whether given User instance supports adding e-mails, provide another method like supportsAddEmail returning false by default and true when overriding addEmail.

like image 64
Tomasz Nurkiewicz Avatar answered Nov 15 '22 00:11

Tomasz Nurkiewicz