2012-02-08 10 views
5

Tôi đang đấu tranh để làm cho công việc này:Java Generics vấn đề nhà máy trừu tượng

public abstract class MapperFactory<M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> { 

    public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) { 

     if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

     throw new IllegalStateException("Mapper not found!"); 
    } 

    public abstract TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper(); 

    public static class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> { 

     @Override 
     public TaskMapper<? extends Message, ? extends Message, ? extends TaskForm> getTaskMapper() { 
      return new MyTaskMapper(); 
     } 

    } 
} 

public interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> { 

    public F fillForm(I msgIn, O msgOut, F taskForm); 

    public O fillMsgOut(F taskForm); 
} 

public class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm > { 

    public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut, 
      MyTaskForm taskForm) { 
     return null; 
    } 

    public OutgoingMessage fillMsgOut(MyTaskForm taskForm) { 
     return null; 
    } 

} 

Vấn đề là một lỗi biên dịch:

Type mismatch: cannot convert from MapperFactory.MyTaskMapperFactory to MapperFactory

trong MapperFactory tôi ở đây:

if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

Bất kỳ ý tưởng làm thế nào để sửa lỗi này?

Dĩ nhiên thay thế:

public static <M extends TaskMapper<? extends Message, ? extends Message, ? extends TaskForm>> MapperFactory<M> getMapperFactory(Message msgIn, Message msgOut) { 

     if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

     throw new IllegalStateException("Mapper not found!"); 
    } 

với:

public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) { 

     if (msgIn.isMyMapper()) 
      return new MyTaskMapperFactory(); 

     throw new IllegalStateException("Mapper not found!"); 
    } 

sẽ làm việc, nhưng đó không phải là câu trả lời mà tôi đang tìm kiếm.

Điều này có vẻ là một vấn đề với mô hình nhà máy chung trừu tượng nói chung. Câu trả lời cung cấp các mẫu nguồn bằng cách sử dụng các đối tượng được tạo tùy chỉnh cũng được hoan nghênh.

+0

'MAPPER' không phải là tên lớp tốt theo quy ước Java. –

+0

Hãy đặt tên lớp của bạn càng nhỏ càng tốt (nhưng vẫn rõ ràng). Và đổi tên 'MAPPER' thành' Mapper'? Các tên lớp lạ/dài chỉ gây nhầm lẫn/làm lộn xộn câu hỏi * và * câu trả lời. – Bohemian

+0

@his MAPPER không phải là tên lớp. Đó là tên của loại chung chung như T trong HashMap

Trả lời

4

Theo Effective Java, 2nd edition, mục 28:

If a type parameter appears only once in a method declaration, replace it with a wildcard.

phương pháp getMapperFactory bạn chỉ sử dụng các tham số loại M trong kiểu trả về. Sau lời khuyên này cho chữ ký phương pháp sau đây, và phương pháp biên dịch:

public static MapperFactory<? extends TaskMapper<Message, ? extends Message, ? extends String>> getMapperFactory(Message msgIn, Message msgOut) 

EDIT: Tôi càng nhìn vào mã, tôi càng nghĩ MapperFactory không nên được tham số. Tham số không được sử dụng trong mã ở đây, getTaskMapper trả về một TaskMapper.

+2

Thậm chí ngắn hơn, chữ ký chỉ có thể là 'public static MapperFactory getMapperFactory()'. Phương thức này không hạn chế bất kỳ tham số kiểu nào nhiều hơn chữ ký lớp cho 'MapperFactory'. Cũng vậy với 'TaskMapper trừu tượng công khai getTaskMapper()'. (Nó cũng có thể là 'công khai trừu tượng M getTaskMapper()', không thể cho biết ý định đằng sau tham số kiểu là gì.) * "Khi nghi ngờ, sử dụng ít generics" * có lẽ là một nguyên tắc tốt. – millimoose

1

Lệnh return hoạt động tốt với một thợ đúc chư:

return (BpmMapperFactory<MAPPER>)new Bpm007PrepareDocTaskMapperFactory(); 

Đó là mã sẽ không bao giờ thực hiện mặc dù trong hình thức hiện tại của nó, bởi vì Bpm007PrepareDocTaskMapper không mở rộng BpmCommonMessageDto, vì vậy msgIn có thể không có khả năng là một thể hiện của Bpm007PrepareDocTaskMapper.

+0

Tôi đã chỉnh sửa phần 'if' cho thông tin, chưa hoàn thành và nó không liên quan ở đây. Bất kỳ cách nào để tránh phôi? –

1

Giải pháp của tôi sẽ được giết càng nhiều các Generics càng tốt với một ngọn lửa:

abstract class MapperFactory<M extends TaskMapper<?, ?, ?>> { 

    public static MapperFactory<?> getMapperFactory(Message msgIn, Message msgOut) { 
     if (msgIn.isMyMapper()) return new MyTaskMapperFactory(); 
     throw new IllegalStateException("Mapper not found!"); 
    } 

    public abstract M getTaskMapper(); 
} 


class MyTaskMapperFactory extends MapperFactory<MyTaskMapper> { 

    @Override 
    public MyTaskMapper getTaskMapper() { 
     return new MyTaskMapper(); 
    } 

} 


interface TaskMapper<I extends Message, O extends Message, F extends TaskForm> { 

    public F fillForm(I msgIn, O msgOut, F taskForm); 

    public O fillMsgOut(F taskForm); 

} 

class MyTaskMapper implements TaskMapper<IncomingMessage, OutgoingMessage, MyTaskForm> { 

    public MyTaskForm fillForm(IncomingMessage msgIn, OutgoingMessage msgOut, MyTaskForm taskForm) { 
     return null; 
    } 

    public OutgoingMessage fillMsgOut(MyTaskForm taskForm) { 
     return null; 
    } 

} 

Nó thực sự không cần thiết phải lặp lại các tham số kiểu của một lớp trong mỗi phương pháp có sử dụng nó nếu bạn không thực sự quan tâm những gì họ đang có hoặc không cần phải hạn chế họ nhiều hơn so với chữ ký lớp.