Como usar o mixin Python corretamente?
Herança e Composição: Um Guia de Programação Orientada a Objetos em Python
por Isaac Rodriguez em 15 de Janeiro de 2024
Neste tutorial, você irá explorar a herança e a composição em Python. A herança e a composição são dois conceitos importantes na programação orientada a objetos que modelam a relação entre duas classes. Eles são os blocos de construção do design orientado a objetos e ajudam os programadores a escreverem código reutilizável.
No final deste tutorial, você irá aprender a:
- Utilizar a herança em Python
- Modelar hierarquias de classes utilizando herança
- Utilizar múltipla herança em Python e compreender suas desvantagens
- Utilizar a composição para criar objetos complexos
- Reutilizar código existente aplicando a composição
- Alterar o comportamento da aplicação em tempo de execução através da composição
O que é Herança e Composição?
A herança e a composição são dois conceitos principais na programação orientada a objetos que modelam a relação entre duas classes. Elas impulsionam o design de uma aplicação e determinam como a aplicação deve evoluir à medida que novos recursos são adicionados ou os requisitos são alterados.
Ambas permitem a reutilização de código, mas o fazem de maneiras diferentes.
O que é Herança?
A herança modela o que é chamado de relação “é um” (“is a”). Isso significa que quando você tem uma classe Derivada
que herda de uma classe Base
, você criou uma relação em que Derivada
é uma versão especializada de Base
.
A herança é representada utilizando a Linguagem de Modelagem Unificada (UML) da seguinte maneira:
Na hierarquia de classes acima, a classe Base
é a classe pai e a classe Derivada
é a classe filha. A classe Derivada
herda todas as características (atributos e métodos) da classe Base
e pode adicionar ou sobrescrever essas características conforme necessário.
A herança permite a reutilização de código, pois você pode criar uma classe filha que herda o código da classe mãe e adicionar ou modificar o comportamento conforme necessário. Isso evita a duplicação de código e facilita a manutenção do código, já que as alterações feitas na classe mãe são automaticamente refletidas nas classes filhas.
Você pode usar a herança em Python criando uma classe filha que herda da classe mãe da seguinte forma:
Na classe Derivada
, você pode adicionar, modificar ou sobrescrever qualquer atributo ou método da classe Base
conforme necessário.
O que é Composição?
A composição modela o que é chamado de relação “tem um” (“has a”). Isso significa que quando uma classe A
tem uma instância de uma classe B
como um de seus atributos, você criou uma relação em que A
tem um objeto B
.
A composição é representada na UML da seguinte maneira:
Na representação acima, a classe A
tem uma instância da classe B
como um de seus atributos. A classe C
também tem uma instância da classe B
como um de seus atributos. Isso permite a criação de objetos complexos, combinando diferentes classes.
A composição permite a reutilização de código, pois você pode criar uma classe que possui objetos de outras classes como atributos. Isso permite que você construa objetos complexos combinando diferentes classes e seus comportamentos. Ao utilizar a composição, você pode acessar os métodos e atributos das classes associadas a partir da classe principal.
Você pode utilizar a composição em Python criando uma classe que possui objetos de outras classes como atributos da seguinte forma:
Na classe A
e C
, você pode acessar os atributos e métodos da instância de B
utilizando a sintaxe self.b.atributo
ou self.b.metodo()
.
Uma Visão Geral da Herança em Python
Python suporta herança simples, o que significa que uma classe pode herdar de apenas uma classe pai. No entanto, a classe pai pode por sua vez herdar de outra classe, formando assim uma hierarquia de classes.
A Superclasse Objeto
Em Python, todas as classes herdam implicitamente da superclasse object
. Isso significa que todas as classes em Python são subclasses de object
. Essa superclasse fornece alguns métodos e atributos básicos que são herdados por todas as classes, como o método __init__()
para inicialização de objetos e o método __str__()
para conversão de objetos em strings.
Quando você define uma classe em Python, ela herda automaticamente da classe object
se você não especificar explicitamente a classe pai.
Exceções São uma Exceção
Existem algumas classes em Python que não herdam diretamente da classe object
, como as classes de exceções. As classes de exceções em Python são subclasses da classe BaseException
, e a classe BaseException
é uma exceção a regra de herança da classe object
.
Criando Hierarquias de Classes
Você pode criar hierarquias de classes em Python definindo uma classe filha que herda da classe mãe. As classes filhas herdam todos os métodos e atributos da classe mãe e podem adicionar ou sobrescrever esses métodos e atributos conforme necessário.
Exemplo:
No exemplo acima, a classe Animal
é a classe mãe, e as classes Cachorro
e Gato
são classes filhas. Ambas as classes filhas herdam o método fazer_barulho()
da classe mãe, mas cada uma delas o implementa de maneira diferente.
Classes Abstratas em Python
Em Python, você também pode criar classes abstratas que não podem ser instanciadas diretamente. Uma classe abstrata é uma classe que possui pelo menos um método abstrato, que é um método que não possui uma implementação na classe abstrata, mas deve ser implementado nas classes filhas.
Para criar uma classe abstrata em Python, utilize o módulo abc
e a classe ABC
como base para a sua classe. Em seguida, utilize o decorator @abstractmethod
para definir os métodos abstratos na classe abstrata. As classes filhas devem implementar esses métodos abstratos.
Exemplo:
No exemplo acima, a classe FiguraGeometrica
é uma classe abstrata que define o método abstrato calcular_area()
. As classes filhas Retangulo
e Circulo
implementam esse método de acordo com suas necessidades. A classe abstrata FiguraGeometrica
não pode ser instanciada diretamente, mas as classes filhas podem ser.
Herdando Múltiplas Classes
Python também suporta herança múltipla, o que significa que uma classe pode herdar de várias classes ao mesmo tempo. Com a herança múltipla, uma classe pode herdar os atributos e métodos de várias classes pai.
No entanto, é importante tomar cuidado ao utilizar herança múltipla, pois ela pode levar a problemas de ambiguidade se duas classes pai tiverem métodos ou atributos com o mesmo nome. Nesses casos, é necessário especificar qual classe pai deve ser utilizada como base para o método ou atributo em questão.
Para herdar de múltiplas classes em Python, basta colocar todas as classes pai dentro dos parênteses após o nome da classe filha.
Exemplo:
No exemplo acima, a classe C
herda de duas classes, A
e B
. Portanto, a classe C
possui os métodos metodo_a()
e metodo_b()
.
Composição em Python
A composição é outra maneira de reutilizar código em programação orientada a objetos. Ao utilizar a composição, uma classe possui uma ou mais instâncias de outras classes como atributos. Essas instâncias são então utilizadas para adicionar funcionalidades à classe principal.
A composição é representada da seguinte forma:
Na representação acima, a classe A
possui uma instância da classe B
como um de seus atributos. A classe A
pode utilizar os métodos e atributos da instância de B
para adicionar comportamento à classe principal.
Ao utilizar a composição, você pode construir objetos complexos combinando diferentes classes e aproveitando as funcionalidades oferecidas por essas classes. Isso permite uma maior flexibilidade e reutilização de código, já que você pode modificar facilmente a composição do objeto, adicionando ou removendo instâncias de outras classes.
Exemplo:
No exemplo acima, a classe Car
possui uma instância da classe Engine
como seu atributo engine
. A classe Car
utiliza os métodos da instância de Engine
(start, stop) para adicionar comportamento à classe principal.
Ao utilizar a composição, você pode construir objetos complexos combinando diferentes classes e suas funcionalidades. Isso permite uma maior flexibilidade e reutilização de código, já que você pode modificar facilmente a composição do objeto, adicionando ou removendo instâncias de outras classes.
Composição é uma ótima alternativa quando a relação entre as classes é “tem um” (“has a”), onde uma classe possui uma instância de outra classe como um atributo.
Escolhendo Entre Herança e Composição em Python
Na programação orientada a objetos em Python, você pode escolher entre herança e composição para modelar a relação entre classes. A escolha entre herança e composição depende da relação entre as classes e dos requisitos do projeto.
Herança para Modelar a Relação “É um” (“Is a”)
A herança é uma boa opção quando a relação entre as classes é “é um” (“is a”), ou seja, quando uma classe é uma versão especializada de outra classe. Nesses casos, a classe filha herda todas as características (atributos e métodos) da classe mãe e pode adicionar ou sobrescrever essas características, conforme necessário.
A herança é útil quando você quer reutilizar código de uma classe mãe em várias classes filhas. Isso evita a duplicação de código e facilita a manutenção do código, já que as alterações feitas na classe mãe são automaticamente refletidas nas classes filhas.
Exemplo:
No exemplo acima, a classe Animal
é a classe mãe e as classes Cachorro
e Gato
são classes filhas. Ambas as classes filhas herdam o atributo nome
da classe mãe. A classe Cachorro
adiciona o método latir()
e a classe Gato
adiciona o método miar()
.
Misturando Funcionalidades com Classes Mixin
Uma classe mixin é uma classe que possui métodos e atributos que podem ser adicionados a outras classes através da herança múltipla. As classes mixin são utilizadas para adicionar funcionalidades a outras classes sem quebrar a hierarquia de classes ou duplicar código.
Exemplo:
No exemplo acima, as classes A
e B
são classes mixin. A classe C
herda as funcionalidades dessas classes mixin através da herança múltipla. Assim, a classe C
possui tanto o método metodo_a()
quanto o método metodo_b()
.
Classes mixin são utilizadas quando você quer adicionar funcionalidades específicas a uma classe sem criar uma complexa hierarquia de classes.
Composição para Modelar a Relação “Tem um” (“Has a”)
A composição é apropriada quando a relação entre as classes é “tem um” (“has a”), ou seja, quando uma classe possui outra classe como um de seus atributos. Nesse caso, a classe principal utiliza os métodos e atributos da instância da classe associada para adicionar funcionalidade à classe principal.
A composição é útil quando você deseja criar objetos complexos combinando diferentes classes e suas funcionalidades. Isso permite uma maior flexibilidade e reutilização de código, já que você pode modificar facilmente a composição do objeto, adicionando ou removendo instâncias de outras classes.
Exemplo:
No exemplo acima, a classe Car
possui uma instância da classe Engine
como seu atributo engine
. A classe Car
utiliza os métodos da instância de Engine
(start, stop) para adicionar comportamento à classe principal.
Composição para Alterar o Comportamento em Tempo de Execução
A composição também pode ser utilizada para alterar o comportamento das classes em tempo de execução. Nesse caso, a classe principal possui um atributo que pode ser trocado por diferentes instâncias de classes associadas, modificando assim o comportamento da classe em diferentes cenários.
Exemplo:
No exemplo acima, a classe MyClass
possui um atributo behavior
que pode ser trocado por diferentes instâncias de classes associadas. O método execute_behavior()
utiliza o método execute()
da instância de behavior
para executar o comportamento da classe.
Escolhendo entre Herança e Composição em Python
Ao escolher entre herança e composição em Python, leve em consideração a relação entre as classes e os requisitos do projeto. Utilize herança quando a relação entre as classes for “é um” (“is a”), ou seja, quando uma classe for uma versão especializada de outra classe. Utilize composição quando a relação entre as classes for “tem um” (“has a”), ou seja, quando uma classe possuir outra classe como um de seus atributos.
Em algumas situações, é possível utilizar herança e composição em conjunto para obter os melhores resultados. Essa escolha deve ser feita com base nas necessidades do projeto e no princípio de design conhecido como Princípio da Composição sobre Herança. Esse princípio defende que a composição geralmente é preferível à herança, pois ela permite uma maior flexibilidade e reutilização de código.
Conclusão
Neste tutorial, você aprendeu sobre herança e composição em Python. A herança e a composição são dois conceitos importantes na programação orientada a objetos que permitem a reutilização de código e o design flexível de classes. A herança modela a relação “é um” (“is a”) entre classes, permitindo a criação de hierarquias de classes e a reutilização de código. A composição modela a relação “tem um” (“has a”) entre classes, permitindo a criação de objetos complexos combinando diferentes classes. Você deve escolher entre herança e composição com base na relação entre as classes e nos requisitos do projeto. Aproveite esses conceitos para criar um código mais organizado, modular e reutilizável em Python.