2010-06-12 3 views
6

제 질문은 단어를 사용하여 설명하기가 쉽지 않습니다. 다행히도 설명하기가 어렵지 않습니다. 그래서 나와 함께 곰 :제네릭과 상속을 적절하게 혼합하여 원하는 결과를 얻는 방법은 무엇입니까?

public interface Command<R> 
{ 
    public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command 
} 

public abstract class BasicCommand<R> implements Command<R> 
{ 
} 

public interface CommandProcessor<C extends Command<?>> 
{ 
    public <R> R process(C<R> command);//this is my question... it's illegal to do, but you understand the idea behind it, right? 
} 

//constrain BasicCommandProcessor to commands that subclass BasicCommand 
public class BasicCommandProcessor<C extends BasicCommand<?>> implements CommandProcessor<C> 
{ 
    //here, only subclasses of BasicCommand should be allowed as arguments but these 
    //BasicCommand object should be parameterized by R, like so: BasicCommand<R> 
    //so the method signature should really be 
    // public <R> R process(BasicCommand<R> command) 
    //which would break the inheritance if the interface's method signature was instead: 
    // public <R> R process(Command<R> command); 
    //I really hope this fully illustrates my conundrum 
    public <R> R process(C<R> command) 
    { 
     return command.execute(); 
    } 
} 

public class CommandContext 
{ 
    public static void main(String... args) 
    { 
     BasicCommandProcessor<BasicCommand<?>> bcp = new BasicCommandProcessor<BasicCommand<?>>(); 
     String textResult = bcp.execute(new BasicCommand<String>() 
     { 
      public String execute() 
      { 
       return "result"; 
      } 
     }); 
     Long numericResult = bcp.execute(new BasicCommand<Long>() 
     { 
      public Long execute() 
      { 
       return 123L; 
      } 
     }); 
    } 
} 

기본적으로, 나는 일반적인 "프로세스"방법은 Command 개체의 일반적인 매개 변수의 유형을 지시하고 싶습니다. 목표는 CommandProcessor의 다른 구현을 Command 인터페이스를 구현하는 특정 클래스로 제한 할 수 있고 동시에 CommandProcessor 인터페이스를 구현하는 모든 클래스의 프로세스 메서드를 호출하고 해당 클래스의 process 객체를 반환 할 수있게하는 것입니다. 매개 변수화 된 Command 개체. 내 설명이 명확한 지 확실하지 않으므로 추가 설명이 필요한 경우 알려 주시기 바랍니다. 나는 "이게 가능할 수 있을까?"라는 질문을 던집니다. 대답이 "아니오"일 경우 가장 좋은 해결 방법이 될 것입니다. (내 생각으로는 몇 가지 생각이 들지만 신선한 아이디어가 필요합니다)

+0

'BasicCommand'가'Command'를 구현하지 않아야합니까? –

+0

Touche, fixed. 그것을 잡아 주셔서 감사합니다! – Andrey

답변

3

불행히도이 작업을 수행 할 수 없습니다. CommandProcessor 인터페이스가 Command으로 정의되기를 원하기 때문에, 구현은 BasicCommand으로 제한 할 수 없으며, 가능하다면 BasicCommandProcessor 서브 클래스는 CommandProcessor 인터페이스를 구현하지 않습니다. Command 인스턴스를 취할 수 있도록 구현해야합니다.

또는 다른 각도에서 CommandProcessor 인터페이스가 제공된 경우 제네릭에서 BasicCommand 인스턴스로만 호출되었음을 보장 할 수 없습니다. 이렇게하려면 구현을 알아야하며, 다형성과 인터페이스의 관점을 피하십시오.

명령의 결과는 매개 변수화 할 수 있지만 구체적인 명령 클래스는 매개 변수화 할 수 없습니다.

public interface Command<R> 
{ 
    public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command 
} 

public abstract class BasicCommand<R> implements Command<R> 
{ 
} 

public interface CommandProcessor 
{ 
    public <R> R process(Command<R> command); 
} 

public class BasicCommandProcessor implements CommandProcessor 
{ 
    public <R> R processBasicCommand(BasicCommand<R> command) 
    { 
     return command.execute(); 
    } 

    public <R> R process(Command<R> command) 
    { 
     return processBasicCommand((BasicCommand<R>)command); 
    } 
} 

가장 간단한 방법은 당신이 필요로하는 특정 유형을 받아들이는 방법을 제공하고, 일반적인 방법으로 그것을 호출하는 것입니다. (위 BasicCommandProcessor를 참조하십시오.)

+0

"... CommandProcessor 인터페이스가 주어지면 범용 함수가 BasicCommand 인스턴스에서만 호출된다는 것을 보장 할 수 없습니다. 이렇게하려면 구현을 알아야하고 다형성과 인터페이스의 관점을 피하십시오." 당연하지. 구현이 유형 매개 변수로 지정된 경우, 서브 클래스는 유형 바인드를 추가로 제한 할 수 있습니다 (예를 들어 나의 대답 참조). 네, 이것은 원시 타입이 대체 원칙을 따르지 않는다는 것을 의미합니다. 컴파일러는 메소드 인수를 전달하기 위해 합성 메소드를 내 보내야합니다. 하지만 그것은 유효한 Java입니다. – meriton

+0

당신이 말하는 것을 봅니다. 구현 세부 사항에 대한 추가 매개 변수 유형을 추가하여 작동하도록 만들 수 있지만 인터페이스가있는 지점을 손상시키는 것은 저에게 있습니다. 내 경험에 비추어 볼 때, 인터페이스의 수가 증가함에 따라 다루기 힘들어 질 수도 있습니다. – mdma

+0

그것은 의도에 따라 다릅니다. CommandProcessor가 인터페이스에서 명령 유형을 갖는 모든 종류의 명령으로 작동 할 수 있다면 실제로 쓸모가 없습니다. 그러나 CommandProcessor가 특정 유형의 명령에서만 작동 할 수있는 경우 (예 : 여기 에서처럼) 인터페이스에서이를 표현하는 것이 적절할 수 있습니다. (자세한 내용은 http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html에서 "generics가 병렬 클래스 계층 구조를 설계하는 데 도움이 되는가?" – meriton

1

는 기본적으로, 나는 일반 "프로세스"방법은 명령 객체의 일반적인 매개 변수의 유형 을 지시하고 싶습니다. CommandProcessor 인스턴스화되면, 실제 입력 등이 Command<String>C 위해 공급 될 수있다 :

이것은 클로징 타입 입력 파라미터로서 명령을 정의하는 개념과 상충된다. 심지어 C<R>의 의미는 다음이 될 것입니다 무엇

class Foo implements Command<String> { 
    ... 
} 

와 같은 제네릭이 아닌 유형을 제공 할 수 있을까요? Foo<R>? Command<String><R>? Command<R>?

그렇다면 어떤 옵션이 있습니까? CommandProcessor은 특정 반환 값의 형태로 작업해야하는 경우, 당신은 할 수 있습니다 :

class CommandProcessor<R, C extends Command<R>> { 
    R process(C command); 
} 

class FancyCommandProcessor<R, C extends FancyCommand<R>> extends CommandProcessor<R,C> { 

} 

을하지만, 난 당신이 CommandProcessor이 명령의 전체 유형의 가족과 함께 작업 할 생각한다.이것은 그 자체는 아무 문제 없을 것입니다 단순히 선언

<R> R process(FancyCommand<R> command); 

그러나 만약, 당신이 process을 무시할 수 있도록 추가 명령의 다른 가족 CommandProcessors 사이의 서브 타입 관계를 원하는, 당신은 자바 제네릭의 표현을 넘어 벤처. 특히 C++의 'template'형식 매개 변수 (실제 형식 인수로 템플릿을 전달할 수 있음) 또는 Command를 확장하는 것으로 알려진 실제 형식 인수가 지정된 Command 형식 매개 변수를 캡처하는 기능이 필요합니다. . 자바는 어느 것도 지원하지 않습니다.

+0

"CommandProcessor를 인스턴스화 할 때 Command 과 같은 실제 유형을 사용해야합니다. C에 공급 됨 " 사실, 틀렸어. [와일드 카드] (http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html) (명령 )는 항상 제공 될 수 있습니다. – Andrey

+0

나는 교정되었고 그에 따라 편집했습니다. 그러나, 그것은 내 주장에서 조금 변경 ... – meriton

+0

당신은 문제를 잘 설명했습니다. 유일한 것은 CommandProcessor가 실제로 처리 할 때 예외를 처리 할 수있는 Command의 반환 유형에 대해 알 필요가 없다는 것입니다. 어떤 경우에는 Command와 함께 유형의 객체를 전달해야합니다. 가능하지 않은 매개 변수가있는 것으로 보입니다. 당신이 백업 upvote. – Andrey

관련 문제