java - puede - Golang: ¿cuál es el punto de las interfaces cuando tienes herencias múltiples
que es herencia en java (4)
Soy un programador de Java, aprendiendo a programar en Go. Hasta ahora, realmente me gusta el lenguaje. MUCHO más que Java.
Pero hay algo de lo que estoy un poco confundido. Java tiene interfaces porque las clases solo pueden heredar de una clase. Dado que Go permite herencia múltiple, ¿cuál es el punto de las interfaces?
Si supertype X es una interfaz, quienquiera que mantenga el código sabe de inmediato que no tiene implementaciones de métodos. Si el supertipo Y es una clase abstracta, quien esté manteniendo el código debe verificar si hay implementaciones de métodos. Entonces es una cosa de documentación / mantenimiento / legibilidad.
Las clases pueden heredar e implementar desde múltiples archivos de clase.
A menos que malinterprete:
public class MyClass extends MySuperClass implements MyInterface, MySecondInterface
El objetivo de las interfaces es permitir una clase completamente abstracta. Tan abstracto que no hay un solo método definido. Usaría una interfaz cuando necesito crear varias clases abstractas con la misma estructura básica. Entonces podría crear instancias de clases que amplíen la clase abstracta, que a su vez implementaría la interfaz.
Esto se hace con la interfaz java.util.Collection
y algunas clases como java.util.ArrayList
y java.util.Stack
implementan esa interfaz. De esta forma, puede almacenar todo tipo de elementos de listas en una Colección. Esta es la razón por la cual ArrayList
tiene un método para addAll(Collection<? extends E> c)
.
Se podría decir que es como ser compatible con objetos simples.
Polimorfismo
Las interfaces permiten que las funciones tengan un parámetro ''marcador de posición'' que puede tomar diferentes estructuras como argumento. Por ejemplo, si struts Man, Woman, Child implementan la interfaz Human, entonces un método con el parámetro Human puede tomar cualquiera de las estructuras Man, Woman, Child como argumento. Por lo tanto, el parámetro de interfaz puede ''transformarse'' en cualquier estructura pasada como argumento siempre que implemente todas las funciones definidas en la interfaz.
Esto es importante porque las interfaces son la única forma de lograr el polimorfismo en Go, ya que no tiene herencia. Entonces, si el Hombre ''extendió'' al Humano (al tenerlo como un campo anónimo), cualquier método que usara al Humano como argumento, no sería capaz de tomar al Hombre como argumento.
Mi confusión se originó en el hecho de que la herencia también es una forma de lograr el polimorfismo en Java, y supuse que ese era el caso aquí también. ¡Estoy corregido!
Las interfaces en Go son muy diferentes de las interfaces en Java.
En Java, una clase tiene que aceptar formalmente implementar una interfaz:
public class Foo implements iFoo
En Go, un tipo de usuario implementa una interfaz simplemente haciéndolo.
Una función o propiedad puede definir lo que se espera:
func DoSomething(r io.Reader) {
buf := make([]byte, 128)
n, err := r.Read(buf)
...
}
A la función DoSomething
se le puede pasar cualquier cosa que implemente la función de Read
que se encuentra en la interfaz io.Reader
, sin que la cosa sepa o no se preocupe por la interfaz. Es responsabilidad de la persona que llama asegurarse de que está pasando algo que implemente la interfaz. Esto se verifica en tiempo de compilación.
Podemos llevar esto un paso más allá. Podemos definir nuestra propia interfaz:
type MyInterface interface {
io.Reader // Include Reader interface
Seek(int) error // Include my own function
}
func DoSomething(r MyInterface) {
buf := make([]byte, 128)
n, err := r.Read(buf)
...
}
Go también es diferente porque no tiene una clase o tipo de objeto . Cualquier tipo declarado por el usuario, ya sea basado en un entero, cadena, estructura, matriz, sector, canal, etc. puede tener métodos asociados.
Go también no tiene la típica herencia de clase a la que normalmente está acostumbrado, pero tiene un par de cosas que son bastante cercanas.
Tipo redeclarado:
type Num int
func (n Num) Print() {
print(n)
}
type Number Num
func (n Number) Print() {
Num(n).Print()
}
Campos anónimos:
type Foo struct {
sync.Mutex
}
func main() {
f := Foo{}
f.Lock()
// ...
f.Unlock()
}