2013-07-18 2 views
2

У меня есть этот дизайн, и я не уверен, почему он не работает.Дженерик Ограниченный Тип Параметр

interface BaseType {} 

interface TypeA extends BaseType {} 

interface TypeB extends BaseType {} 

interface Query<T extends BaseType> { 
    public String get(); 
} 

interface Result<T extends BaseType> { 
    public String get(); 
} 

interface Service<T extends BaseType> { 
    public Result<T> get(Query<T> query); 
} 

class SomeResult implements Result<TypeA> { 
    private String s; 
    public SomeResult(String s) { this.s = s; } 
    public String get() { return this.s; } 
} 

class SomeQuery implements Query<TypeA> { 
    public String get() { return "blah"; } 
} 

class SomeQuery2 implements Query<TypeA> { 
    public String get() { return "blah2"; } 
} 

class SomeService implements Service<TypeA> { 
    /** OK -- but notice the ambiguous parameter type */ 
    /* 
    public SomeResult get(Query<TypeA> query) { 
     if (query instanceof SomeQuery) return new SomeResult(query.get()); 
     else return null; 
    } 
    */ 

    /** NOT OK -- but this is the parameter I want to keep; notice SomeQuery IS-A Query<TypeA> */ 
    public SomeResult get(SomeQuery query) { return new SomeResult(query.get()); }; 
    /** 
    * Main.java:27: error: SomeService is not abstract and does not override abstract method get(Query<TypeA>) in Service 
    * class SomeService implements Service<TypeA> { 
    *^
    * 1 error 
    */ 
} 

public class Main { 
    public static void main(String args[]) { 
     SomeQuery someQuery = new SomeQuery(); 
     SomeQuery2 someQuery2 = new SomeQuery2(); 
     SomeService someService = new SomeService(); 
     System.out.println(someService.get(someQuery).get()); 
    } 
} 

Я новичок в дженериках и не совсем понимаю, какой контракт я нарушаю здесь. Я хочу, чтобы служба была жестко ограничена, и даже если я могу связать возвращаемый тип, я не могу сделать этого для параметра. Это означает, что мне нужно выполнить проверку instanceof внутри службы, чтобы убедиться, что я получаю правильный параметр. Я хочу этого избежать. Есть идеи?

ответ

1

Вам разрешено сделать тип возвращаемого метода более специфичным из-за return type covariance, но вы не можете изменить параметры метода без изменения его подписи. Вот почему компилятор жалуется, что вы не реализовали get(Query<TypeA>), когда вы изменили его на get(SomeQuery). Вам нужно сделать Service более гибким для того, чтобы получить то, что вы хотите:

interface Service<T extends BaseType, Q extends Query<T>> { 
    public Result<T> get(Q query); 
} 

class SomeService implements Service<TypeA, SomeQuery> { 

    @Override 
    public SomeResult get(SomeQuery query) { 
     ... 
    } 
} 

отметить также, что суженный тип возвращаемого значения не имеет значения при кодировании интерфейса: когда SomeService набираются, как Service<TypeA, SomeQuery>, get будет по-прежнему возврат Result<TypeA>. Возможно, вы решите произвести аналогичное изменение для типа результата:

interface Service<T extends BaseType, Q extends Query<T>, R extends Result<T>> { 
    public R get(Q query); 
} 

class SomeService implements Service<TypeA, SomeQuery, SomeResult> { 

    @Override 
    public SomeResult get(SomeQuery query) { 
     ... 
    } 
} 
+1

+1. Или, говоря иначе, 'SomeService' is-a' Service 'и' SomeQuery2' is-a 'Query ', поэтому он должен иметь возможность работать: 'Service service = new SomeService(); service.get (new SomeQuery2()); ' –

+0

Спасибо. Это имеет смысл. – bdas

Смежные вопросы