简体   繁体   中英

Generics confusion

Apologies for the generic title, I can't really think of a way to explain this.

I'd like to model a scenario where a system provides facilities to users, which have associated policies applied to requests against those facilities.

public interface Facility {
    public List<Policy> getPolicies();
}
public interface Policy {
    public void apply(Facility facility, Request request);
}
public interface Request {

}

But a request can only be sensible for a particular type of facility, and a policy can really only apply to a type of facility and a type of request specific to that type of facility.

public interface Facility<F extends Facility<F>> {
    public List<Policy<F, ? extends Request<F>>> getPolicies();
}
public interface Policy<F extends Facility<F>, R extends Request<F>> {
    public void apply(F facility, R request);
}
public interface Request<F extends Facility<F>> {

}

But I'd also like to be able to specify policies overall, such that they can apply to any Facility supertype.

public interface Facility<F extends Facility<F>> {
    public List<Policy<? super F, ? extends Request<F>>> getPolicies();
}

But in reality you're only ever going to want to query the policies that apply to a particular type of request for the facility.

public interface Facility<F extends Facility<F>> {
    public <R extends Request<F>> List<Policy<? super F, R>> getPolicies();
}

My problem is now I'm so confused with all the generics and I'm not able to even create a policy class that applies to all Facilities, which would be something like this, if it were legal

public class GeneralPolicy implements Policy<T extends Facility<T>, Request<T>>

How do I go about making it possible to associate types of facility, policy and request in such a way that makes sense according to the description above? I'm sure people will ask for clarification, I've battled with this long enough that I'm probably not explaining something, or completely missing an obvious point.

If I read this correctly, what you really want to do is get all the policies that work for R.

public interface Facility<F extends Facility<F>> {
    public <R extends Request<F>> List<Policy<? super F, R>> getPolicies();
}

Unfortunately, thanks to type erasure, you can't. At runtime, the compiler doesn't know what R is.

What you can do, however, is pass the class in:

public interface Facility<F extends Facility<F>> {
    public <R extends Request<F>> List<Policy<? super F, R>> getPolicies(Class<R> requestClass);
}

Then Policy would need to return its request type as well:

public interface Policy<F extends Facility<F>, R extends Request<F>> {
    public void apply(F facility, R request);

    public Class<R> getRequestClass();
}

The implementation of facility can then though the list of available policies, check if the policy's request type matches the actual requested type, and return that subset.

For global policies, the policy could return Request.class. For specific ones, MyRequest.class.

Furthermore, I'd say that Facility (at least the way you have it there) doesn't need to be genericized, and it'll make the code much simpler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM