2010-12-11 29 views
7

Vì vậy, tôi đã hỏi câu hỏi này trước đây nhưng tôi đã có một sai lầm trong mã mà hầu hết mọi người chọn lên, chứ không phải là vấn đề chính nó.Java: thay thế một phân lớp/subtype của một tham số khi vượt qua một phương thức?

Dù sao, tôi đang cố gắng ghi đè phương thức giao diện trong một lớp. Tuy nhiên, tôi muốn kiểu tham số trong phương thức ghi đè là một lớp con của kiểu tham số như được định nghĩa trong phương thức overriden.

Giao diện:

public interface Observer { 
public void update(ComponentUpdateEvent updateEvent) throws Exception; 
} 

Trong khi lớp đó sẽ ghi đè phương pháp này là:

public class ConsoleDrawer extends Drawer { 

//... 

@Override 
public void update(ConsoleUpdateEvent updateEvent) throws Exception { 
    if (this.componentType != updateEvent.getComponentType()) { 
    throw new Exception("ComponentType Mismatch."); 
    } 
    else { 
    messages = updateEvent.getComponentState(); 
    } 
} 

//... 

} 

ConsoleUpdateEvent là một lớp con của ComponentUpdateEvent.

Bây giờ, tôi chỉ có thể có phương thức update() trong ConsoleDrawer lấy ComponentUpdateEvent làm tham số và sau đó truyền nó vào một ConsoleUpdateEvent nhưng tôi đang tìm một giải pháp gọn nhẹ hơn nếu có thể. Bất kỳ trợ giúp sẽ được đánh giá cao. Cảm ơn bạn.

+5

Tôi không tin điều này là có thể vì nó đi ngược lại nguyên tắc của một giao diện (tức là các lớp thực hiện giao diện sẽ khớp hoàn toàn với tất cả các chữ ký phương thức được chỉ định bởi giao diện). Tuy nhiên, tôi sẽ xem câu hỏi này vì tôi rất quan tâm để xem liệu có người nào khác sẽ chứng minh tôi sai hay không. – DGH

Trả lời

2

Bạn có thể thử cách sau. @Deprecated tạo ra một cảnh báo nếu trình biên dịch biết bạn sẽ gọi phương thức đầu tiên chứ không phải là phương thức thứ hai.

@Override @Deprecated 
public void update(ComponentUpdateEvent updateEvent) { 
    // throws a ClassCastException if its not the right type. 
    update((ConsoleUpdateEvent) updateEvent); 
} 

public void update(ConsoleUpdateEvent updateEvent) { 
    messages = updateEvent.getComponentState(); 
} 

BTW: Bạn không nên chỉ đặt ném ngoại lệ trên mọi thứ. Nó chắc chắn không phải là thực hành tốt nhất.

EDIT: Tôi đã triển khai giải pháp khác cho vấn đề này hoạt động tốt với OSGi nhưng có thể hoạt động ở mọi nơi.

Máy quan sát đăng ký chính nó với Nhà môi giới và dự kiến ​​sẽ tìm các phương pháp có chú thích như ObserverCallback.

ví dụ:

public class ConsoleDrawer extends Drawer { 
@ObserverCallback 
public void onConsoleUpdateEvent(ConsoleUpdateEvent updateEvent) { 
    messages = updateEvent.getComponentState(); 
} 
} 

public class DeviceDrawer extends Drawer { 
@ObserverCallback 
public void onDeviceUpdateEvent(DeviceUpdateEvent updateEvent) { 
    // do something. 
} 
} 

Trong trường hợp đầu tiên, người môi giới tìm ra phương thức với @ObserverCallback lấy một đối số. Đây là loại duy nhất mà Nhà môi giới sẽ vượt qua. Lớp thứ hai mong đợi một loại khác. Các nhà quan sát có thể có nhiều phương pháp/loại cho phép họ xử lý các thông điệp khác nhau theo các phương pháp khác nhau phù hợp với loại đó. Bạn cũng biết rằng bạn sẽ không bao giờ nhận được kiểu dữ liệu mà bạn không mong đợi.

+0

Cá nhân tôi (và nhiều người khác tôi đã nói) không thích sử dụng thẻ Không được chấp nhận cho bất kỳ mục đích nào khác ngoài ý định ban đầu: các phương pháp đánh dấu đã sử dụng hợp lệ nhưng hiện không còn được dùng nữa. Sử dụng nó cho một cái gì đó khác như thế này cảm thấy hacker-ish. – DGH

+0

@DGH, Phương thức được sử dụng hợp lệ (đối với phụ huynh) nhưng không còn hợp lệ cho lớp này nữa. ;) Tôi lấy điểm của bạn mặc dù. Lý tưởng nhất là sẽ có một thẻ tạo ra lỗi trình biên dịch. Thậm chí tốt hơn là nên thiết kế phương thức update() để tất cả việc triển khai thực hiện được hợp đồng. –

+0

Cảm ơn bạn đã đề xuất. Sử dụng giải pháp đầu tiên; Tôi đổi tên phương thức cập nhật thứ hai thành addEventMessages void (ConsoleUpdateEvent) {// ...} và điều đó có vẻ hoạt động khá tốt. – carnun

7

Bạn không thể. Đây không phải là Eiffel. Vấn đề là bạn có thể sử dụng giao diện để gọi phương thức triển khai với một kiểu không tương thích. Vì vậy, các thông số covariant không được phép. Các tham số contravariant cũng không được phép, nhưng dễ dàng hơn để cung cấp quá tải. Loại trả về biến đổi được cho phép (từ 1,5).

Bạn có thể parameterise giao diện:

public interface Observer<T extends ComponentEvent> { 
    void update(T event) throws Exception; 
} 

Ngoài ra, sử dụng một giao diện có ý nghĩa hơn:

public interface ConsoleObserver { 
    void update(ConsoleEvent event) throws Exception; 
} 
+1

Tìm thấy câu trả lời chi tiết tại đây http://stackoverflow.com/a/9421315/1276636 – Sufian

2

Đi theo nguyên tắc OOP, một sub-class nên được sử dụng trong cách chính xác giống như lớp cha. ví dụ:

Observer ob = new ConsoleDrawer(); 
ob.update(new ComponentUpdateEvent()); // This needs to work always. 

Tuy nhiên, nếu Java là cho phép bạn sử dụng một subtype của tham số khi trọng một phương pháp, sau đó nó sẽ phơi bày mã của bạn đối với trường hợp các phương pháp trọng (trong subclass) sẽ từ chối tham số đầu vào (ComponentUpdateEvent trong trường hợp trên). Vì vậy, bạn sẽ không bao giờ chắc chắn rằng nó an toàn để gọi update() hay không trên một tham chiếu Observer.

Do đó, giải pháp logic duy nhất là chấp nhận tham số lớp cha, gõ-kiểm tra nó và sau đó truyền nó đến loại phụ được yêu cầu.

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