How to implement two different interfaces with the same method signature

Suppose I need to implement two different interfaces declared in two different packages (in two different separate projects).

I have in package 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 } 

And in package 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 } 

In my main package

 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 ! } 

How to cope with this situation?

+5
source share
2 answers

The FAQ is mentioned

Experience with other languages ​​tells us that using different methods with the same name but with different signatures was sometimes useful, but could also be confusing and fragile in practice. Only name matching and type consistency was the main simplifying solution in a Go type system .

In your case, you will satisfy both interfaces.

You can check whether an object (type of interface) corresponds to another type of A.Doer interface by doing:

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

OP adds:

But the logic implemented in the Do method to satisfy A is completely different from the one in B

Then you need to implement a wrapper around the object:

  • a DoerA that has its C object as a field and implements A.Do() in a way that satisfies how A.Do() should work
  • a DoerB that has the same C object as a field and implements B.Do() in a way that satisfies how B.Do() should work

This way you will know which Doer will go to a function that expects A.Doer or B.Doer .
You will not need to implement the Do() method on your original C object, which will not be able to handle the different logic of A.Do() and B.Do() .

+7
source

By definition, you satisfy both :

Type A Go satisfies the interface, implementing the methods of this interface, nothing more. This property allows you to define and use interfaces without the need to modify existing code. It allows you to create structural typing, which helps to separate problems and improves code reuse, and also simplifies the construction of patterns that arise as the code develops. The semantics of interfaces is one of the main reasons for a reasonable, easy perception.

So, bearing in mind, you can:

a) Add comments on interface methods that define your expectations in logic (see io.Reader interface or a good example)

b) Add an additional interface called ImplementsDoerA and ImplementsDoerB to the interfaces (also mentioned in the FAQ).

+3
source

Source: https://habr.com/ru/post/1211816/


All Articles