简体   繁体   中英

java composite design pattern with generics

I have two interfaces which are generic, IComparable<T> , with method public boolean gt(T t) and ICombinable<T> , with method public T combine(T t) , and a third interface IPreferenceValue<T> which extends both these interfaces, ie, IPreferenceValue<T> extends IComparable<T>, ICombinable<T> , so that a preference value of type T can be compared and combined with other T 's. I have two concrete implementations of IPreferenceValue, one being a single-valued implementation : IntegerValue implements IPreferenceValue<IntegerValue> and the other being a List of preference values: PreferenceVector<S extends IPreferenceValue<S>> implements IPreferenceValue<PreferenceVector<S>> .

Elsewhere I have an algorithm that performs various things on IPreferenceValues and I want to treat the single valued and list valued Preference values the same way via the interface, like the Composite Design Pattern. I also want to have some sort of Factory that would create IPreferenceValues based on some parameter, ie, create a single-value object, or create a list-valued object. However when I am creating these PreferenceValues, I don't care about the type Parameter, I just want to create objects of type IPreferenceValue, the factory would return the concrete implementation - and just use the interface to interact with the objects.

However I am having some difficulty getting this to work. Firstly if I declare my values using the raw type IPreferenceValue, I am getting these warnings - " IPreferenceValue is a raw type. References to generic type IPreferenceValue<T> should be parameterized ". Are these warnings avoidable? Elsewhere, where I declare them as IPreferenceValue<?> , I get the following error: The method gt(capture#6-of ?) in the type IComparable<capture#6-of ?> is not applicable for the arguments (IPreferenceLevel<capture#7-of ?>) . Any advice or pointers greatly appreciated...

EDIT: Here is where I get the second error ( The method gt(capture#12-of ?) in the type IComparable<capture#12-of ?> is not applicable for the arguments (IPreferenceLevel<capture#13-of ?>) )

private IPreferenceLevel<?> calculateMinValue()
{
    IPreferenceLevel<?> min = null;
    for (IPreferenceLevel<?> value : tupleToValueMap.values())
    {
        if ((min == null) || (min.gt(value).equals(Comparison.TRUE)))
        {
            min = value;
        }
    }
    return min;
}

However even when I put in a type for this method, ie, if i rewrite as follows -

private <X> IPreferenceLevel<X> calculateMinValue()
{
    IPreferenceLevel<X> min = null; ...

This still doesn't compile - The method gt(X) in the type IComparable<X> is not applicable for the arguments (IPreferenceLevel<capture#10-of ?>)

You haven't given enough context about the specific error cases for me to be able to definitively point out what the issue is. So I'll have to give more general pointers.

Firstly, the raw type warning is correct. Raw types arguably only exist for backwards compatibility, and you should never use them in new code. An IPreferenceValue always has a generic type - if you have no idea what it is and don't care, return it as an IPreferenceValue<?> as you've already done. This is fine, and essentially communicates that you don't know/care about the parameter. (Of course, if you know what it might be, then by all means provide a more specific parameter.)

The second error seems legitimate - you need to pass in a T but you're trying to pass in an IPreferenceValue<T> .

But also, once you fix this you'll still have a problem. The underlying error occurs in a completely different way and is not too unusual with generics. You've got a reference to an IPreferenceValue<?> and you're trying to call its gt method, which is defined to take a T . But you've just said that you have absolutely no idea what T is for that object (which is why you used the wildcard) - if you don't know what the generic parameter is, how can you pass in anything to it and know it's of the correct type?

Specifically, you're trying to compare the contents of the tupleToValueMap with each other. In order to do that legally, their generic type parameters would have to be the same - how would you compare a IPreferenceLevel<IntegerValue> with a IPreferenceLevel<PreferenceVector<S>> ?

So you should declare the type of the tupleToValueMap more specifically, giving it a concrete generic parameter for the preference levels rather than ? . If it turns out that you can't do this because you're putting multiple types of preference level in there - then the compiler error is right, you can't compare them against each other safely.

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