DEV Community

Cover image for Programação Orientada a Objetos: Polimorfismo
Fabiano Santos Florentino
Fabiano Santos Florentino

Posted on

1

Programação Orientada a Objetos: Polimorfismo

A programação orientada a objetos (POO) é amplamente utilizada para criar sistemas modulares e reutilizáveis. Dentro desse paradigma, um dos pilares mais importantes é o polimorfismo, que, em Golang, pode ser implementado através de interfaces. Este artigo explora o conceito de polimorfismo em Golang e como ele pode ser aplicado para criar sistemas flexíveis e expansíveis.

O que é Polimorfismo?

Polimorfismo, derivado do grego poli (muitos) e morfos (formas), é um conceito fundamental na programação orientada a objetos (POO). Ele permite que diferentes tipos de objetos respondam ao mesmo conjunto de operações de maneiras específicas. Em termos práticos, isso significa que podemos definir um método com o mesmo nome em várias classes diferentes, e cada classe pode ter sua própria implementação desse método. Isso facilita a criação de código flexível e reutilizável, pois podemos tratar objetos de diferentes tipos de maneira uniforme, sem precisar conhecer suas implementações específicas.

Como funciona em Golang?

Em Golang, o polimorfismo é alcançado através do uso de interfaces. Diferente de linguagens orientadas a objetos tradicionais que utilizam herança, Golang permite que tipos diferentes implementem a mesma interface, desde que eles definam os métodos especificados pela interface.

O que é uma Interface?

Uma interface em Golang é um tipo que especifica um conjunto de métodos. Qualquer tipo que implemente esses métodos é considerado como implementando a interface.

Para ilustrar, imagine que estamos desenvolvendo um sistema de pagamentos capaz de processar diferentes métodos, como pagamentos via cartão de crédito e boleto bancário. Podemos definir uma interface chamada PaymentProcessor que declara um método ProcessPayment().

package main

import "fmt"

// Definindo a interface PaymentProcessor que declara o método ProcessPayment
type PaymentProcessor interface {
  ProcessPayment(amount float64)
}

// Struct para pagamento via cartão de crédito
type CreditCard struct{}

// Implementação do método ProcessPayment para CreditCard
func (c CreditCard) ProcessPayment(amount float64) {
  // Taxa de 2% aplicada no valor original
  finalAmount := amount * 1.02
  fmt.Printf("Processando pagamento via cartão de crédito. Valor original: R$%.2f, Valor final com taxa: R$%.2f\n", amount, finalAmount)
}

// Struct para pagamento via boleto bancário
type Boleto struct{}

// Implementação do método ProcessPayment para Boleto
func (b Boleto) ProcessPayment(amount float64) {
  // Desconto de 5% no valor original
  finalAmount := amount * 0.95
  fmt.Printf("Processando pagamento via boleto. Valor original: R$%.2f, Valor final com desconto: R$%.2f\n", amount, finalAmount)
}

// Função que aceita qualquer tipo que implemente a interface PaymentProcessor
func ProcessarPagamento(p PaymentProcessor, amount float64) {
  p.ProcessPayment(amount)
}

func main() {
  cartao := CreditCard{}
  boleto := Boleto{}

  valor := 100.00 // Exemplo de valor de pagamento

  // Utilizando polimorfismo para processar diferentes tipos de pagamento
  ProcessarPagamento(cartao, valor) // Saída: Processando pagamento via cartão de crédito. Valor original: R$100.00, Valor final com taxa: R$102.00
  ProcessarPagamento(boleto, valor) // Saída: Processando pagamento via boleto. Valor original: R$100.00, Valor final com desconto: R$95.00
}
Enter fullscreen mode Exit fullscreen mode

Aqui, temos dois tipos (CreditCard e Boleto), cada um com sua própria implementação do método ProcessPayment(). A função ProcessarPagamento() pode aceitar qualquer tipo que implemente a interface PaymentProcessor, o que nos dá flexibilidade para adicionar novos métodos de pagamento sem modificar o código existente.

Polimorfismo em Tempo de Execução

Em Golang, o polimorfismo ocorre principalmente em tempo de execução, pois o tipo exato que implementa a interface é resolvido dinamicamente. Em outro exemplo onde novos tipos de pagamentos podem ser facilmente adicionados.

Imagine que queremos suportar um novo método de pagamento, como o Pix. Basta criarmos uma nova struct Pix e implementar o método ProcessPayment().

package main

import "fmt"

// Definindo a interface PaymentProcessor que declara o método ProcessPayment
type PaymentProcessor interface {
  ProcessPayment(amount float64)
}

// Struct para pagamento via Pix
type Pix struct{}

// Implementação do método ProcessPayment para Pix
func (p Pix) ProcessPayment(amount float64) {
  // Desconto de 1% no valor original
  finalAmount := amount * 0.99
  fmt.Printf("Processando pagamento via Pix. Valor original: R$%.2f, Valor final com desconto: R$%.2f\n", amount, finalAmount)
}

// Função que aceita qualquer tipo que implemente a interface PaymentProcessor
func ProcessarPagamento(p PaymentProcessor, amount float64) {
  p.ProcessPayment(amount)
}

func main() {
  pix := Pix{}
  valor := 100.00 // Exemplo de valor de pagamento

  // Processando o novo tipo de pagamento via Pix
  ProcessarPagamento(pix, valor) // Saída: Processando pagamento via Pix. Valor original: R$100.00, Valor final com desconto: R$99.00
}
Enter fullscreen mode Exit fullscreen mode

Sem precisar alterar a função ProcessarPagamento, podemos facilmente integrar o novo tipo de pagamento, mostrando o poder do polimorfismo em Golang.

Benefícios do Polimorfismo em Golang

  • Flexibilidade: O polimorfismo permite que novos comportamentos sejam adicionados sem modificar o código existente. Adicionamos novos tipos como Pix, sem precisar alterar a função ProcessarPagamento.
  • Expansibilidade: Podemos adicionar quantos tipos forem necessários que implementem a interface PaymentProcessor, criando um sistema que pode crescer de forma orgânica.
  • Reutilização de código: A lógica principal pode ser reutilizada para diferentes tipos, evitando duplicação de código.
  • Manutenção simplificada: Como a lógica está centralizada na interface, a manutenção se torna mais fácil, já que o código não depende de implementações específicas.

Conclusão

O polimorfismo permite que diferentes tipos sejam tratados de forma uniforme através de interfaces. Isso promove a flexibilidade e a extensibilidade do código, permitindo que novos tipos sejam adicionados sem modificar o código existente que depende da interface.

Ao entender e utilizar o polimorfismo, você poderá desenvolver software mais flexível e preparado para crescer com as necessidades do seu projeto, criando soluções eficientes e escaláveis.

Referências

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay