Programação Orientada a Objetos: Herança
Tags: programming, braziliandevs, poo
Published: 2024-06-27 17:39:01

---
title: "Programação Orientada a Objetos: Herança"
published: true
description: Herança
series: Programação Orientada a Objetos
tags: programming, braziliandevs, poo
cover_image: https://i.ibb.co/m69Qnf6/Screenshot-2024-06-26-at-21-39-20.png
---

# Herança

Herança é um dos pilares da programação orientada a objetos, e é uma das formas de reutilização de código. A herança é um mecanismo que permite que uma classe herde atributos e métodos de outra classe, chamada de superclasse ou classe base. A classe que herda os atributos e métodos é chamada de subclasse ou classe derivada.

## Principais Conceitos

- **Superclasse (Classe Base):** A classe cujos atributos e métodos são herdados por outras classes. É a classe “pai”.
- **Subclasse (Classe Derivada):** A classe que herda atributos e métodos da superclasse. É a classe “filha”.
- **Herança Simples:** Quando uma subclasse herda de uma única superclasse.
- **Herança Múltipla:** Quando uma subclasse herda de mais de uma superclasse. Nem todas as linguagens de programação suportam herança múltipla devido à sua complexidade.
- **Sobrescrita de Método:** A subclasse pode fornecer uma implementação específica de um método que já existe na superclasse.

## Herança & Composição não são a mesma coisa

Composição e herança são duas formas de reutilização de código em programação orientada a objetos. A herança é uma forma de reutilização de código que permite que uma classe herde atributos e métodos de outra classe. A composição é uma forma de reutilização de código que permite que uma classe contenha objetos de outras classes. A composição é geralmente preferida à herança, pois é mais flexível e menos propensa a problemas de design.

## Como funciona em Go

Go `não possui herança` como em linguagens orientadas a objetos clássicas. Ao invés de herança, Go utiliza composição e interfaces para alcançar o mesmo comportamento. Geralmente, a composição é feita através de structs (estruturas) e interfaces.

```go
package main

import "fmt"

// Veiculo é uma interface que define um método dados que retorna uma string
type Veiculo interface {
	dados() string
}

// Carro é uma struct que representa um carro
type Carro struct {
	marca  string
	modelo string
}

// dados é um método que retorna uma string com os dados do carro
func (c Carro) dados() string {
	return fmt.Sprintf("Marca: %s, Modelo: %s", c.marca, c.modelo)
}

// Hatch é uma struct que representa um carro do tipo hatch
type Hatch struct {
	Carro
	portas int
}

// dados é um método que retorna uma string com os dados do carro hatch
func (h Hatch) dados() string {
	return fmt.Sprintf("Marca: %s, Modelo: %s, Portas: %d", h.marca, h.modelo, h.portas)
}

// Sedan é uma struct que representa um carro do tipo sedan
type Sedan struct {
	Carro
	portaMalas int
}

// dados é um método que retorna uma string com os dados do carro sedan
func (s Sedan) dados() string {
	return fmt.Sprintf("Marca: %s, Modelo: %s, Porta Malas: %d", s.marca, s.modelo, s.portaMalas)
}

type Conversivel struct {
	Carro
	capota bool
}

func (c Conversivel) dados() string {
	return fmt.Sprintf("%s, Capota: %t", c.Carro.dados(), c.capota)
}

// imprimirDados é uma função que recebe um veículo e imprime os dados do veículo
func imprimirDados(v Veiculo) {
	fmt.Println(v.dados())
}

func main() {
	// Acessando atributos
	hatch := Hatch{Carro{"Chevrolet", "Onix"}, 4}
	sedan := Sedan{Carro{"Honda", "Civic"}, 500}

	// Acessando métodos dados da struct Carro de forma explícita
	conversivel := Conversivel{Carro{"Fiat", "Spyder"}, true}

	imprimirDados(hatch)
	imprimirDados(sedan)
	imprimirDados(conversivel)
}
```

```shell
heranca main 29m ➜ go run main.go
Marca: Chevrolet, Modelo: Onix, Portas: 4
Marca: Honda, Modelo: Civic, Porta Malas: 500
Marca: Fiat, Modelo: Spyder, Capota: true
```

Neste exemplo, temos uma interface `Veiculo` que define um método `dados` que retorna uma string. Temos também uma struct `Carro` que representa um carro e um método `dados` que retorna uma string com os dados do carro. As structs `Hatch` e `Sedan` representam carros do tipo hatch e sedan, respectivamente. Ambas as structs `Hatch` e `Sedan` incorporam a struct `Carro` através da composição. Cada uma das structs `Hatch` e `Sedan` tem um método `dados` que retorna uma string com os dados do carro do tipo hatch ou sedan. A função `imprimirDados` recebe um veículo e imprime os dados do veículo.

Com a composição você pode acessar tantos os atributos quanto os métodos da struct incorporada. No entanto, se houver um método com o mesmo nome ele será sobrescrito.Você pode acessar o método da struct incorporada de forma explícita `c.Carro.dados()`.

```go
func (h Hatch) dados() string {
	return fmt.Sprintf("%s, Portas: %d", h.Carro.dados(), h.portas)
}
```

## Conclusão

A herança é um mecanismo importante da programação orientada a objetos que permite a reutilização de código. No entanto, a herança pode levar a problemas de design, como acoplamento excessivo e hierarquias de classes profundas. Em Go, a linguagem não possui herança como em linguagens orientadas a objetos clássicas. Em vez disso, Go utiliza composição e interfaces para alcançar o mesmo comportamento. A composição é geralmente preferida à herança, pois é mais flexível e menos propensa a problemas de design.

## Projeto

[Github](https://github.com/fabianoflorentino/poo/tree/main/heranca)

## Referências

[Wikipédia (Herança)](https://pt.wikipedia.org/wiki/Herança_(programação_orientada_a_objetos))
[Wikipédia (Composição, herança e delegação)](https://pt.wikipedia.org/wiki/Programação_orientada_a_objetos#Composição,_herança_e_delegação)
[Go: Composição vs Herança (Vinicius Pacheco)](https://medium.com/@ViniciusPach_97728/go-composição-vs-herança-2e8b78928c26)
[Effective Go](https://go.dev/doc/effective_go#embedding)
[The Go Programming Language Specification](https://go.dev/ref/spec#Struct_types)
[Go by Example](https://gobyexample.com/struct-embedding)