1. Interface-Oriented Programming
1.1 Characteristics
Interface-oriented programming emphasizes interaction between modules through interfaces. First, the caller specifies a set of method signatures; then, the callee implements that set of methods.
What sets interface programming apart from other programming styles is that it focuses on methods, not attributes. In many programming scenarios, methods are defined around attributes. As shown below:

But in interface programming it is the exact opposite: methods sit at the core, while attributes can be defined freely and extended. The same interface is implemented on different data structures. As shown below:

In addition, the wording itself shows that interface-oriented programming is an interface-centric programming paradigm.
1.2 Advantages
- Module decoupling
Through interface abstraction, the dependencies between modules are made explicit. The boundaries between modules are clearer, and each module is more independent.
- Maintainability
An interface hides the concrete implementation; as long as each module keeps the interface unchanged, its internal logic can be freely refactored.
- Easy to extend, easy to upgrade
As long as the same set of methods is implemented, a module can be extended or upgraded very conveniently.
- Easy to test
When writing unit tests, external dependencies need to be masked, and an interface is very easy to mock. Code written in an interface-oriented style is much easier to unit test.
2. Interface in Go
An interface in Go is a type that aggregates a set of methods.
2.1 Declaration and Implementation
You can declare an interface with the interface keyword plus a set of method signatures. A method signature means all the information that uniquely identifies a method: its name, parameters, return values, and so on. Here is the declaration of an Animal interface:
| |
Interfaces in Go are implemented implicitly. You do not need to specify which interface is being inherited; as long as some type in the same package implements all the methods of the interface, that type is said to implement the interface. In the example below, the Cat type implements the Animal interface:
| |
When using it, you can declare a variable of type Animal, point it at a Cat, and then call the methods of the interface.
| |
2.2 Receiver Types
Go allows methods to be defined on a type, and the Receiver refers to the type that the method accepts — for example, Cat in the example above.
In the example above, both i = &Cat{} and i = Cat{} work; Go performs the conversion automatically. The exception is when the Receiver is a pointer type but the assignment is a value type. Because Go uses value passing, after the assignment the address obtained points to the address of the copy, not the address of the intended data, and the compiler reports an error:
| |
Built-in types cannot be used as a Receiver. Receivers come in two kinds, value and pointer, and the two can also be mixed.
- Value Receiver
| |
- Pointer Receiver
| |
When implementing an interface you will face the choice between these two kinds. Passing a pointer seems more efficient, but it also means the operation is more dangerous. In scenarios where the data does not need to be modified, a value Receiver should be used whenever possible.
2.3 The Empty Interface
What is special about the empty interface is that interface{} can accept a value of any type. This feature looks like something only a dynamic language would have, but Go is a statically typed language. At compile time, Go validates interfaces strictly.
| |
The empty interface is very useful when accepting or returning parameters of an uncertain type. But an uncertain type also brings maintenance cost. In a project, we should avoid using the empty interface as much as possible to keep the project more maintainable.
2.4 Type Determination
Since interface{} can accept a value of any type, during program execution it is quite likely that you need to know the dynamic value type of the interface. There are two ways to determine the type:
- Assertion
| |
- switch
| |
Note that here, when the Cat and Dog values are type-checked against Animal, the result is true.
3. Composition of Interfaces
| |
An interface can also nest other interfaces. A type that implements this interface must provide all the methods defined by every interface. This technique is very useful in projects.
