Is it possible to make a specific method working only with a specific constructor?

Viewed 64

I have a class called User.java

public class User {

    public User(Context context) {

    }

    public User() {

    }
    
    public void getUserId(){
        
    }
    
    public void getUserName(){
        
    }

}

If I create an object of user class then I can reach to all methods such as getUserId and getUserName

User user_1 = new User(this);
user_1.getUserId();
user_1.getUserName();   

User user_2 = new User();
user_2.getUserId();
user_2.getUserName();

The main question is can I get getUserName only if I called a constructor that has one parameter? But if I call a constructor that does not have a parameter then I can't get getUserName. Is it possible in Java?

2 Answers

No, it is not possible. But you could use interfaces to say for instance LimitedUser and FullUser

public interface LimitedUser {
  int userId();
}

public interface FullUser extends LimitedUser {
  String getUsername();
}

Then use factory methods on for instance the User implementation

public class User implements FullUser {

  private final int id;
  private final String username;
 
  private User(int id, String username) {
    this.id = id;
    this.username = username;
  }

  public static LimitedUser createLimitedUser(int id) {
    return new User(id, null);  
  }

  public static FullUser createFullUser(int id, String username) {
    return new User(id, username);
  }

  public int getId() {
    return id;
  }

  public String getUsername() {
    return username;
  }

}

There are multiple ways to achieve (roughly) what you want.

The easy, but possibly annoying way is to throw an Exception whenever a "forbidden" method is called:

public String getUserName(){
  if (someRequiredContext == null) {
    throw new IllegalStateException("method not allowed!");
  }
  // do stuff
}

This "works", but doesn't help the user avoid calling those methods, since there's no easy way for them to know if they can call getuserName on a given User object.

The more involved version would be to have two classes (for example User and UserWithContext), but then you can't instantiate them the right way. But you could use factory methods instead of constructors:

public abstract class User {
  User() { ... };

  public static User createUser() {
    return new BasicUser();
  };

  public static UserWithContext createUser(Context context) {
    return new UserWithContext(context);
  }

  public String getId() { ... }
}

class BasicUser extends User { // this class need not be public!
}

public class UserWithContext extends User {
  UserWithContext(Context context) { ... }
  
  public String getuserName() { ... };
}

This way the type will inform the users of your API which methods are allowed with a given User object.

Related