Programação Orientada a Objetos: Polimorfismo

Fabiano Santos Florentino - Oct 30 - - Dev Community

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

. . . . . . . . . . . . . . . . . . . . .
Terabox Video Player