2010-06-12 27 views
6

Câu hỏi của tôi không dễ giải thích khi sử dụng các từ, may mắn thay nó không quá khó để chứng minh. Vì vậy, hãy theo tôi:Làm thế nào để kết hợp chính xác generics và thừa kế để có được kết quả mong muốn?

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; 
      } 
     }); 
    } 
} 

Về cơ bản, tôi muốn phương thức "quy trình" chung quy định loại thông số chung của đối tượng Lệnh. Mục đích là để có thể hạn chế việc triển khai CommandProcessor khác nhau đối với các lớp nhất định thực hiện giao diện Command và đồng thời có thể gọi phương thức quy trình của bất kỳ lớp nào thực hiện giao diện CommandProcessor và nó trả về đối tượng kiểu được chỉ định bởi parametarized Command đối tượng. Tôi không chắc chắn nếu lời giải thích của tôi là đủ rõ ràng, vì vậy xin vui lòng cho tôi biết nếu cần giải thích thêm. Tôi đoán, câu hỏi là "Liệu điều này có thể làm được không?" Nếu câu trả lời là "Không", đó là công việc tốt nhất (tôi nghĩ về một đôi vợ chồng, nhưng tôi muốn một số ý tưởng mới)

+0

Không nên 'BasicCommand' triển khai' Command'? –

+0

Touche, cố định. Cảm ơn vì đã bắt được! – Andrey

Trả lời

3

Thật không may, bạn không thể làm điều này. Vì bạn muốn giao diện CommandProcessor được xác định theo điều khoản Command, nên bạn cần chuẩn bị sẵn sàng để lấy bất kỳ loại nào Command - generics không thể giới hạn số này thành BasicCommand - nếu có thể, thì lớp con BasicCommandProcessor sẽ không triển khai giao diện CommandProcessor.

Hoặc, từ một góc khác, được cung cấp giao diện CommandProcessor, sẽ không thể cho các generics đảm bảo rằng điều này chỉ được gọi với BasicCommand trường hợp. Để làm được điều này, cần phải biết sự implemnetation, và sẽ đi ngược lại điểm đa hình và các giao diện.

Bạn có thể tham số hóa kết quả của lệnh, chứ không phải lớp lệnh cụ thể.

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); 
    } 
} 

Cách tiếp cận đơn giản nhất là cung cấp phương thức chấp nhận loại cụ thể bạn cần và gọi phương thức đó theo phương pháp chung. (Xem BasicCommandProcessor ở trên.)

+0

"... đưa ra một giao diện CommandProcessor, nó không thể cho generics để đảm bảo rằng điều này chỉ được gọi với BasicCommand trường hợp. Để làm điều này sẽ cần phải biết implemnetation, và sẽ đi ngược lại điểm của đa hình và giao diện." Tất nhiên là thế rồi. Nếu việc triển khai được chỉ định làm tham số kiểu, một lớp con có thể hạn chế thêm kiểu ràng buộc, xem câu trả lời của tôi cho một ví dụ. Có, điều này có nghĩa là các kiểu thô không phù hợp với nguyên lý thay thế, và trình biên dịch được yêu cầu phát ra một phương thức tổng hợp để đưa ra đối số phương thức. Nhưng nó là hợp lệ Java. – meriton

+0

Tôi thấy những gì bạn đang nói. Nó có thể được thực hiện để làm việc bằng cách thêm các kiểu tham số bổ sung cho các chi tiết thực hiện, nhưng với tôi mà làm giảm điểm của việc có một giao diện. Theo kinh nghiệm của tôi, nó cũng có thể trở nên khó sử dụng khi số lượng giao diện tăng lên. – mdma

+0

Nó phụ thuộc vào mục đích. Nếu CommandProcessor có thể làm việc với tất cả các loại lệnh có kiểu lệnh trong giao diện thực sự là vô dụng. Tuy nhiên, nếu một CommandProcessor chỉ có thể làm việc với một số loại lệnh nhất định (có vẻ như trường hợp ở đây), thể hiện rằng trong giao diện có thể thích hợp. (Xem "Làm generics giúp thiết kế hệ thống phân cấp lớp song song?" Tại http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html) – meriton

1

Về cơ bản, tôi muốn chung "quá trình" phương pháp để ra lệnh loại của tham số chung của Bộ chỉ huy đối tượng.

Đây là mâu thuẫn với khái niệm về xác định lệnh as type tham số để loại kèm theo: Khi instantiating một CommandProcessor, một loại thực tế như Command<String> có thể được cung cấp cho C. Thậm chí có thể cung cấp loại không chung chung như

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

Ý nghĩa của C<R> là gì? Foo<R>? Command<String><R>? Command<R>?

Vì vậy, bạn có các tùy chọn nào? Nếu một CommandProcessor chỉ cần làm việc với một kiểu trả về cụ thể, bạn có thể làm:

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

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

} 

Tuy nhiên, tôi nghi ngờ bạn muốn có một CommandProcessor để làm việc với toàn bộ gia đình loại lệnh.Điều này tự nó sẽ không có vấn đề, chỉ cần tuyên bố:

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

Tuy nhiên, nếu bạn thêm muốn có một mối quan hệ kiểu phụ giữa CommandProcessors cho các gia đình khác nhau của lệnh, do đó bạn có thể ghi đè process, bạn mạo hiểm vượt quá biểu cảm của Java Generics. Cụ thể, bạn cần hoặc tương đương với các tham số kiểu của mẫu C++ '(cho phép truyền mẫu như đối số kiểu thực), hoặc khả năng nắm bắt tham số kiểu của Lệnh được đưa ra một đối số kiểu thực tế được biết là mở rộng Lệnh . Java cũng không hỗ trợ.

+0

"Đó là, khi instantiating một CommandProcessor, một loại thực tế như Command phải được được cung cấp cho C " Thực ra, bạn đã sai. [Thẻ hoang dã] (http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html) (Lệnh ) luôn có thể được cung cấp ... – Andrey

+0

Tôi đã sửa và chỉnh sửa tương ứng. Tuy nhiên, nó thay đổi rất ít trong đối số của tôi ... – meriton

+0

Bạn đã mô tả vấn đề tốt. Điều duy nhất là CommandProcessor không thực sự cần biết về kiểu trả về của Command mà nó có thể đối phó với EXCEPT khi xử lý chúng trong trường hợp nó chỉ cần truyền đối tượng của kiểu mà Command đã được tham số hóa mà không thể làm điều đó. Upvote bạn sao lưu. – Andrey

Các vấn đề liên quan