Pregunta

¿Cuál es su opinión sobre esta decisión de diseño? ¿Qué ventajas tiene y qué desventajas?

Enlaces:

¿Fue útil?

Solución

En un comentario, se preguntó si la idea de incrustación era suficiente para "reemplazar la herencia por completo". Yo diría que la respuesta a esa pregunta es "sí". Hace unos años jugué muy brevemente con un sistema TCL OO llamado Montar, que utilizó composición y delegación con la exclusión de la herencia. Snit sigue siendo muy diferente del enfoque de GO, pero en ese sentido tienen un terreno filosófico común. Es un mecanismo para unir piezas de funcionalidad y responsabilidad, no una jerarquía para las clases.

Como otros han declarado, se trata realmente de qué tipo de prácticas de programación quieren apoyar los diseñadores de idiomas. Todas esas opciones vienen con sus propios pros y contras; No creo que "las mejores prácticas" sean una frase que necesariamente se aplica aquí. Probablemente veremos a alguien desarrollar una capa de herencia para ir eventualmente.

(Para cualquier lectora familiarizado con TCL, sentí que es un partido un poco más cercano a la "sensación" del idioma que [incr Tcl] estaba. TCL tiene que ver con la delegación, al menos para mi forma de pensar).

Otros consejos

los Pandilla de 4El principio crucial es "preferir composición a la herencia"; Vamos hace lo sigues ;-).

Los únicos usos reales para la herencia son:

  • Polimorfismo

    • El sistema de "tipificación de pato estático" de Go's Interface resuelve este problema
  • Prestado implementación de otra clase

    • Para esto es lo que es la incrustación

El enfoque de GO no mapa exactamente 1 a 1, considere este ejemplo clásico de herencia y polimorfismo en Java (basado en esto):

//roughly in Java (omitting lots of irrelevant details)
//WARNING: don't use at all, not even as a test

abstract class BankAccount
{
    int balance; //in cents
    void Deposit(int money)
    {
        balance += money;
    }

    void withdraw(int money)
    {
        if(money > maxAllowedWithdrawl())
            throw new NotEnoughMoneyException();
        balance -= money;
    }

    abstract int maxAllowedWithdrawl();
}

class Account extends BankAccount
{
    int maxAllowedWithdrawl()
    {
        return balance;
    }
}

class OverdraftAccount extends BankAccount
{
    int overdraft; //amount of negative money allowed

    int maxAllowedWithdrawl()
    {
        return balance + overdraft;
    }
}

Aquí, la herencia y el polimorfismo se combinan, y no se puede traducir esto sin cambiar la estructura subyacente.

No he profundizado profundamente en Go, pero supongo que se vería algo así:

//roughly Go? .... no?
//for illustrative purposes only; not likely to compile
//
//WARNING: This is totally wrong; it's programming Java in Go

type Account interface {
    AddToBalance(int)
    MaxWithdraw() int
}

func Deposit(account Account, amount int) {
    account.AddToBalance(amount)
}

func Withdraw(account Account, amount int) error {
    if account.MaxWithdraw() < amount {
        return errors.New("Overdraft!")
    }
    account.AddToBalance(-amount)
    return nil
}

type BankAccount {
    balance int
}

func (account *BankAccount) AddToBalance(amount int) {
    account.balance += amount;
}

type RegularAccount {
    *BankAccount
}

func (account *RegularAccount) MaxWithdraw() int {
    return account.balance //assuming it's allowed
}

type OverdraftAccount {
    *BankAccount
    overdraft int
}

func (account *OverdraftAccount) MaxWithdraw() int {
    return account.balance + account.overdraft
}

Según la nota, esta es una forma totalmente incorrecta de codificar ya que uno está haciendo Java en GO. Si uno escribiera tal cosa en Go, probablemente se organizaría muy diferente a esto.

La incrustación proporciona delegación automática. Esto en sí mismo no es suficiente para reemplazar la herencia, ya que la incrustación no proporciona forma de polimorfismo. Las interfaces GO proporcionan polimorfismo, son un poco diferentes a las interfaces a las que puede estar utilizando (algunas personas las comparan con la escritura de pato o la tipificación estructural).

En otros idiomas, las jerarquías de herencia deben diseñarse cuidadosamente porque los cambios son amplios y, por lo tanto, difíciles de hacer. Go evita estas trampas mientras proporciona una alternativa poderosa.

Aquí hay un artículo que profundiza en OOP con Go un poco más: http://nathany.com/good

Estoy aprendiendo sobre Go, pero como estás pidiendo una opinión, ofreceré una basada en lo que sé hasta ahora. La incrustación parece ser típica de muchas otras cosas en GO, lo cual es un apoyo lingüístico explícito para las mejores prácticas que ya se están haciendo en los idiomas existentes. Por ejemplo, como señaló Alex Martelli, la pandilla de 4 dice "prefiere la composición a la herencia". Go no solo elimina la herencia, sino que hace que la composición sea más fácil y más poderosa que en C ++/Java/C#.

He sido perplejo por comentarios como "Go proporciona nada nuevo que ya no puedo hacer en el idioma X" y "¿Por qué necesitamos otro idioma?" Me parece que en un sentido, Go no proporciona nada nuevo que no se pudiera hacer antes con algún trabajo, pero en otro sentido, lo nuevo es que GO facilitará y alentará el uso de las mejores técnicas que son ya en la práctica usando otros idiomas.

La gente ha solicitado enlaces a información sobre la incrustación en GO.

Aquí hay un documento de "GO efectivo" donde se discute la incrustación y donde se proporcionan ejemplos concretos.

http://golang.org/doc/effective_go.html#embedding

El ejemplo tiene más sentido cuando ya tiene una buena comprensión de las interfaces y tipos de GO, pero puede fingirlo pensando en una interfaz como un nombre para un conjunto de métodos y si piensa en una estructura como similar a una estructura C.

Para obtener más información sobre las estructuras, puede ver la especificación del lenguaje GO, que menciona explícitamente a los miembros sin nombre de estructuras como tipos integrados:

http://golang.org/ref/spec#struct_types

Hasta ahora solo lo he usado como una forma conveniente de poner una estructura en otra sin tener que usar un nombre de campo para la estructura interna, cuando un nombre de campo no agregaría ningún valor al código fuente. En el ejercicio de programación a continuación, estoy agrupando un tipo de propuesta dentro de un tipo que tiene una propuesta y un canal de respuesta.

https://github.com/ecashin/go-getting/blob/master/bpaxos.go#30

Me gusta.

El lenguaje que usa afecta sus patrones de pensamiento. (Simplemente solicite a un programador C que implemente el "recuento de palabras". Probablemente usarán una lista vinculada, luego cambian a un árbol binario para su rendimiento. Pero cada programador de Java/Ruby/Python usará un diccionario/hash. El lenguaje ha afectado su cerebros tanto que no pueden pensar en usar ninguna otra estructura de datos).

Con la herencia, debes construir, comenzar con lo abstracto y luego subclasearlo a los detalles. Su código útil real estará enterrado en un nivel de clase N de profundidad. Esto hace que sea difícil usar una "parte" de un objeto, porque no puede reutilizar el código sin arrastrar en las clases de los padres.

En Go, puede 'modelar' sus clases de esta manera (con interfaces). Pero no (no puede) codificar de esta manera.

En cambio, puede usar la incrustación. Su código se puede dividir en pequeños módulos aislados, cada uno con sus propios datos. Esto hace que la reutilización sea trivial. Esta modularidad tiene poco que ver con sus objetos "grandes". (es decir, GO, puede escribir un método "Quack ()" que ni siquiera sabe sobre su clase de pato. Pero en un lenguaje OOP típico, no puede declarar "mi implementación de duck.quack () no tiene dependencias en Cualquier otro método de pato ")

En Go, esto constantemente obliga al programador a pensar en la modularidad. Esto lleva a programas que tienen un bajo acoplamiento. El bajo acoplamiento facilita mucho el mantenimiento. ("Oh, mira, duck.quack () es realmente largo y complejo, pero al menos sé que no depende del resto del pato").

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top