wesleyy
wesleyy

Reputation: 2735

Wrap different subclasses with same additional field

Let's say I have some abstract class User, and then subclasses Owner and Client. Each of the two subclasses have some specific fields, but they both inherit common fields from the User. This is all OK, but in a specific situation I'd like to be able to wrap any instance of User with another field. Here is the example.

User.java

public abstract class User {

    private String email;

    private String password;

    private String name;

}

Client.java

public class Client extends User {

    private String salary;

    private String profit;

}

Owner.java

public class Owner extends User {

    private int numberOfClients;

    private double averageClientSalary;

}

Now in a specific case, I'd like to be able to wrap such instances with a login token. So no matter if it is a Client or the Owner instance, it should receive another field loginToken on top of all it's fields.

The use-case would be something like this.

Client client = new Client(email, password, name, salary, profit);

String loginToken = "123abc456";

UserLogin clientLogin = new UserLogin(client);
clientLogin.setLoginToken(loginToken);

// now this should be possible
clientLogin.getEmail(); // base class field
clientLogin.getSalary(); // derived class field
clientLogin.getLoginToken(); // field from a wrapper

So this UserLogin should be able to receive any subclass of User as constructor argument, and remain all of it's fields, just add the extra one, ie. loginToken.

Would something like this be possible and how?

Basically, what would the UserLogin class look like?

Upvotes: 1

Views: 92

Answers (1)

davidxxx
davidxxx

Reputation: 131326

For base class fields and wrapper class fields (or to be precise getters as private fields are not accessible from subclasses) , you can add delegation methods in the wrapper UserLogin class.
But you could not use getters of the subclass as the wrapper manipulates a User declared variable.

public class UserLogin {

    private User user;
    private String token;

    public UserLogin(User user, String token) {
        this.user = user;
        this.token = token;
    }

    public String getEmail() {
        return user.getEmail();
    }    

    public String getLoginToken() {
        return token;
    }

    // not possible for derived fields
    public String getSalary() {
        return user.getSalary();
    }

}

As workaround to do such a thing you could make UserLogin a generic class that provides a method that returns an instance of the specific User class.

For example :

public class UserLogin<T extends User> {

    private T user;
    private String token;

    public UserLogin(T user, String token) {
        this.user = user;
        this.token = token;
    }

    public String getEmail() {
        return user.getEmail();
    }

    public T getConcreteUser() {
        return user;
    }

    public String getLoginToken() {
        return token;
    }    

}

You can now invoke :

UserLogin<Client> clientLogin = new UserLogin<>(new Client(), "token");

clientLogin.getEmail(); 
clientLogin.getConcreteUser()
           .getSalary(); 
clientLogin.getLoginToken(); 

Upvotes: 2

Related Questions