2015-01-24 16 views
5

Giả sử rằng tôi phải triển khai hai giao diện khác nhau được khai báo trong hai gói khác nhau (trong hai dự án riêng biệt khác nhau).Cách triển khai hai giao diện khác nhau với cùng một chữ ký phương thức

tôi có trong gói A

package A 

type interface Doer { 
    Do() string 
} 

func FuncA(Doer doer) { 
    // Do some logic here using doer.Do() result 

    // The Doer interface that doer should implement, 
    // is the A.Doer 
} 

Và trong gói B

package B 

type interface Doer { 
    Do() string 
} 

function FuncB(Doer doer) { 
    // some logic using doer.Do() result 

    // The Doer interface that doer should implement, 
    // is the B.Doer 
} 

Trong main gói của tôi

package main 

import (
    "path/to/A" 
    "path/to/B" 
) 

type C int 

// this method implement both A.Doer and B.Doer but 
// the implementation of Do here is the one required by A ! 
func (c C) Do() string { 
    return "C now Imppement both A and B" 
} 

func main() { 
    c := C(0) 
    A.FuncA(c) 
    B.FuncB(c) // the logic implemented by C.Do method will causes a bug here ! 
} 

Làm thế nào để đối phó với tình huống này?

+2

Hoàn toàn không có gì để xử lý: ** Bất kỳ loại ** nào có phương thức 'Do() string' thực hiện * cả hai giao diện' A.Doer' và 'B.Doer'. – Volker

+0

Tôi nghĩ rằng bạn là đúng @Volker, không có sửa chữa cho điều đó, và tình trạng này có thể xảy ra trong bất kỳ ngôn ngữ có sử dụng giao diện ('java' ví dụ). – tarrsalah

Trả lời

6

Như Experience FAQ mentions

với các ngôn ngữ khác nói với chúng tôi rằng có nhiều phương pháp có cùng tên nhưng chữ ký khác nhau đôi khi là hữu ích nhưng nó cũng có thể gây nhầm lẫn và mong manh trong thực tế. Chỉ khớp với tên và yêu cầu nhất quán trong các loại là quyết định đơn giản hóa chính trong hệ thống loại của Go.

Trong trường hợp của bạn, bạn sẽ thỏa mãn cả hai giao diện.

Bạn có thể giúp bạn có thể kiểm tra xem một đối tượng (một loại giao diện) thỏa mãn một giao diện kiểu A.Doer, bằng cách thực hiện:

if _, ok := obj.(A.Doer); ok { 
} 

Các OP cho biết thêm:

Nhưng logic được thực hiện theo phương pháp Do để đáp ứng A hoàn toàn khác với phương thức B.

Sau đó, bạn cần phải thực hiện một wrapper xung quanh bạn đối tượng:

  • một DoerA, trong đó có đối tượng của bạn C như một lĩnh vực, và thực hiện A.Do() một cách đáp ứng như thế nào A.Do() là nghĩa vụ phải làm việc
  • a DoerB, có cùng một đối tượng C làm trường và triển khai B.Do() theo cách thỏa mãn cách B.Do() được cho là hoạt động

Bằng cách đó, bạn sẽ biết Người dùng nào cần chuyển đến một chức năng mong đợi một số A.Doer hoặc B.Doer.
Bạn sẽ không phải triển khai phương thức Do() trên đối tượng gốc C của mình, điều này sẽ không thể đối phó với logic khác nhau của A.Do()B.Do().

+0

nhưng logic được thực hiện trong phương thức 'Do' để thỏa mãn' A 'hoàn toàn khác với một trong' B'. – tarrsalah

+0

@tarrsalah Tôi đã chỉnh sửa câu trả lời. – VonC

+0

Cảm ơn @VonC, tôi cũng vậy, tôi đã thêm nhiều mã để làm rõ vấn đề. – tarrsalah

3

Theo định nghĩa, you are satisfying both:

Một Go loại đáp ứng một giao diện bằng cách thực hiện các phương pháp của giao diện đó, không có gì hơn. Thuộc tính này cho phép các giao diện được định nghĩa và sử dụng mà không phải sửa đổi mã hiện có. Nó cho phép một kiểu gõ cấu trúc thúc đẩy sự tách biệt các mối quan tâm và cải thiện việc sử dụng lại mã, và làm cho nó dễ dàng hơn để xây dựng trên các mẫu xuất hiện khi mã phát triển. Ngữ nghĩa của giao diện là một trong những lý do chính cho cảm giác nhẹ nhàng, nhẹ nhàng của Go.

Như vậy, với ý nghĩ đó, bạn có thể:

a) Thêm ý kiến ​​cho các phương pháp giao diện xác định mong đợi của bạn về logic (xem giao diện io.Reader hoặc một ví dụ điển hình)

b) Thêm một phương thức bổ sung được gọi là ImplementsDoerA và ImplementsDoerB trên các giao diện (cũng được đề cập trong phần Câu hỏi thường gặp).

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