用相同的附加字段包装不同的子类

时间:2018-02-11 19:06:58

标签: java inheritance design-patterns

假设我有一些抽象类User,然后是子类OwnerClient。两个子类中的每一个都有一些特定字段,但它们都继承了User中的公共字段。这一切都很好,但在特定情况下,我希望能够将User的任何实例与另一个字段包装起来。这是一个例子。

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;

}

现在在特定情况下,我希望能够使用登录令牌包装此类实例。因此,无论它是Client还是Owner实例,它都应该在其所有字段之上接收另一个字段loginToken

用例就是这样的。

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

所以这个UserLogin应该能够接收User的任何子类作为构造函数参数,并保留其所有字段,只需添加额外的字段,即。 loginToken

这样的事情会有可能吗?

基本上,UserLogin类看起来像什么?

1 个答案:

答案 0 :(得分:2)

对于基类字段和包装类字段(或者为了无法从子类访问private字段而准确获取字段),您可以在包装器UserLogin类中添加委派方法。
但是你不能使用子类的getter,因为包装器操作User声明的变量。

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();
    }

}

作为执行此类操作的解决方法,您可以使UserLogin成为一个泛型类,该类提供返回特定User类的实例的方法。

例如:

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

}

您现在可以调用:

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

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