开发者

Specify Generics in interface extends

开发者 https://www.devze.com 2023-02-20 02:26 出处:网络
Should I specify the concrete type for generic types when extending an interface with another interface?

Should I specify the concrete type for generic types when extending an interface with another interface?

What I mean is, if I have an interface:

public interface Repo<T>{
      Collection<T> search(String params);
      T get(String id);
}

and then a whole bunch specific Repositories, like ClientRepo, CustomerRepo, etc... is it reasonable to specify the type T when extending this interface, e.g.:

public interface ClientRepo extends Repo<Client>{
}
public interface CustomerRepo extends Repo<Customer>{
}

where Client and Customer are just some classes.

Did anyone have a similar problem? I mean I could do:

public interface ClientRepo<T> extends Repo<T>{
}

Addendum: Perhaps I should make my intent for having sp开发者_开发知识库ecific Repos (e.g. ClientRepo) more clear. There is another interface called RepoFactory that returns appropriate Repo to the client, e.g.:

public interface RepoFactory{
      ClientRepo createClientRepo();
      CustomerRepo createCustomerRepo();
}

This factory is implemented by implementors which in turn, provide the appropriate implementations of the concrete Repos.

In fact from the above you could say that the interface Repo<T> is not used by the client of the api.

Confusing enough I hope!!! Sorry :(


I've found a lot more utility in doing

public interface SomeRepo<T> extends Repo<T>{
}

Than in extending interfaces via

public interface ClientRepo extends Repo<Client>{
}
public interface CustomerRepo extends Repo<Customer>{
}

That said, I've done both in the past, and will likely wind up doing both in the future. If you detect too much duplicate code in the latter solution, I'd do my best to replace it with the former solution.

If you want any practical issues, it seems that compilers have a harder time realizing that `public interface ClientRepo extends Repo' can be compatible with Repo. It doesn't happen too often (but when it does it takes a number of attempts to get the generics interfacing right).


Well it depends if your extending interface/class could be generic, too. In your example I would assume that you want to do

public interface ClientRepo extends Repo<Client>{
}

Because with

public interface ClientRepo<T> extends Repo<T>{
}

You could do things like

ClientRepo<Customer> 

which is probably not the desired behaviour.


The purpose of generic interfaces (and generics on the whole) is to have a single generic implementation. I.e, even though your interface might have multiple implementations, they should all handle every valid parameter class.

If you remove the parameter in a subsequent layer of interfaces, it kind of defeats the idea of having a generic interface in the first place. After all, you could simply do:

 public interface Repo {
      Collection search(String params);
      Object get(String id);
 }

 public interface ClientRepo {
      Collection<Client> search(String params);
      Client get(String id);
 }

Of course if you have external code that supports parametrised operations on any Repo implementation, having a generic interface could still be useful. But you can also argue that these operations should be part of the Repo interface.

All in all, it's workable and isn't hard to justify but it looks a bit awkward to me: just by looking at your example, it's difficult to figure out what your intent is, which is always a sign of warning.


You could define types properly

interface BaseType { }
interface Client extends BaseType {}
Then, you could define
interface Repo<T extends BaseType> {
    Collection<T> search(String params);
    T get(String id);
}
interface ClientRepo extends Repo<Client> { }
And with implementation
ClientRepo c = new ClientRepo() {
    @Override
    public Collection<Client> search(String params) {// implementation here
    }
    @Override
    public Client get(String id) {// implementation here
    }
};
obtain a stricter type checking.


Turns out the solution I was looking for was simply to throw out all my specialized interfaces:

public interface RepoFactory{
    Repo<Client> createClientRepo();
    Repo<Customer> createCustomerRepo(); }

This way I get to both keep my static type-checking to enforce the api and also gain an additional flexibility for implementations of my Factory.

0

精彩评论

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