O que é Abstração e Como Ela Ajuda a Manter Sistemas Complexos Organizados?

Agora que analisamos encapsulamento, herança e polimorfismo, vamos discutir o próximo conceito chave da programação orientada a objetos – abstração. Abstração é o processo de ocultar detalhes complexos de implementação e mostrar apenas as características essenciais de um objeto ou sistema. Pense nisso como focar no que algo faz em vez de como faz. Abstração não se limita ao Python. É um conceito de programação que pode ser implementado em muitas linguagens que suportam programação orientada a objetos. Para ilustrar a abstração, imagine que você está dirigindo um carro. Quando você está no banco do motorista, você interage com partes essenciais como o volante, a alavanca de câmbio e os pedais do acelerador e do freio. Você não precisa saber os detalhes intrincados de como o engine funciona, como a transmission troca as marchas ou a física por trás do sistema de frenagem, pois todos esses são os detalhes complexos de implementação. Isso é uma abstração em ação! Ela fornece uma interface simplificada para você interagir com um sistema complexo. No caso de um carro novamente, a interface simplificada é o volante, os freios e o acelerador, enquanto o sistema complexo é o próprio carro. Quanto à forma como o Python implementa abstração, ele o faz por meio do módulo abc. Este módulo fornece a classe ABC (que significa “abstract base class”) e o decorador @abstractmethod. ABC é a classe que deve ser herdada, mas você não pode criar objetos diretos a partir dela. É o que define uma interface comum de métodos e propriedades que suas subclasses devem implementar. Por outro lado, um método abstrato é um método declarado em uma Abstract Base Class (ABC) usando o decorador @abstractmethod. Ele pode não ter implementação ou ter uma implementação padrão básica. No entanto, qualquer subclasse deve sobrescrevê-lo para ser considerada concreta e instanciável, mesmo que uma implementação padrão seja fornecida. Aqui está a sintaxe básica de classe abstrata em Python:
from abc import ABC, abstractmethod

# Define an abstract base class
class AbstractClass(ABC):
    @abstractmethod
    def abstract_method(self):
        pass

# Concrete subclass that implements the abstract method
class ConcreteClassOne(AbstractClass):
    def abstract_method(self):
        print('Implementation in ConcreteClassOne')

# Another concrete subclass
class ConcreteClassTwo(AbstractClass):
    def abstract_method(self):
        print('Implementation in ConcreteClassTwo')
Aqui está um exemplo básico:
from abc import ABC, abstractmethod

class Animal(ABC): # Inherits from abstract base class
   @abstractmethod # Abstract method decorator
   def make_sound(self):  # The method subclasses must override
       pass

# Concrete class that will override the abstract method
class Dog(Animal):
   def make_sound(self):
       print('Woof!')

# Another concrete class that will override the abstract method
class Cat(Animal):
   def make_sound(self):
       print('Meow!')

# Another concrete class that will override the abstract method
class Monkey(Animal):
   def make_sound(self):
       print('Ooh ooh aah aah!')

# Create instances of each concrete class
animals = [Dog(), Cat(), Monkey()]

# Loop through the instances to call the make_sound method
for animal in animals:
   animal.make_sound()

# Output:
# Woof!
# Meow!
# Ooh ooh aah aah!
Neste exemplo:
  • Estamos importando a classe ABC e abstractmethod do módulo abc.
  • Em seguida, criamos uma classe Animal que herda de ABC e criamos um método abstrato make_sound nela que cada subclasse de Animal deve sobrescrever.
  • Criamos as classes concretas Dog, Cat e Monkey, que devem sobrescrever o método abstrato make_sound.
  • Instanciamos as classes concretas e chamamos seu método make_sound para mostrar como cada uma delas implementa o método abstrato make_sound de sua própria maneira.
Lembre-se de que você não pode criar uma instância da classe Animal. Veja o que acontece se você tentar fazer isso:
dog = Animal() 
# TypeError: Can't instantiate abstract class Animal 
# without an implementation for abstract method 'make_sound'
A mesma regra se aplica às subclasses que não fornecem uma implementação para o método abstrato. Mesmo que você defina uma subclasse de Animal, você não pode instanciá-la até que ela sobrescreva make_sound. Aqui está um exemplo mostrando isso:
class Bird(Animal):
    pass

bird = Bird()
# TypeError: Can't instantiate abstract class Bird 
# without an implementation for abstract method 'make_sound'
Aqui está outro exemplo, desta vez com um atributo de instância que você pode passar para as instâncias dos métodos concretos:
from abc import ABC, abstractmethod

# The blueprint for any toy that can speak
class TalkingToy(ABC):
   def __init__(self, name):
       self.name = name
   @abstractmethod
   def speak(self):
       pass

class RobotToy(TalkingToy):
   def speak(self):
       print(f'{self.name} says beep boop! I am a robot!')

class TeddyBearToy(TalkingToy):
   def speak(self):
       print(f"{self.name} says hug me! I'm cuddly!")

class DinosaurToy(TalkingToy):
   def speak(self):
       print(f'{self.name} says ROOOOAR!')

# Create toys
rusty = RobotToy('Rusty')
fluffy = TeddyBearToy('Fluffy')
rex = DinosaurToy('Rex')

toys = [rusty, fluffy, rex]
for toy in toys:
   toy.speak()

# Output:
# Rusty says beep boop! I am a robot!
# Fluffy says hug me! I'm cuddly!
# Rex says ROOOOAR!
Neste exemplo: 
  • Temos uma classe base abstrata TalkingToy que define um modelo para qualquer brinquedo que possa falar.
  • As subclasses RobotToy, TeddyBearToy e DinosaurToy implementam o método speak de sua própria maneira.
  • Quando criamos instâncias dessas subclasses e chamamos o método speak, cada brinquedo fala de uma maneira única.
Em conclusão, a abstração em Python simplifica sistemas complexos aumentando a reutilização. Você viu como pode reutilizar um único método de uma classe abstrata em várias subclasses enquanto força cada subclasse a fornecer seu comportamento específico. Esta abordagem mantém seu código organizado, flexível e mais fácil de manter, especialmente à medida que sua aplicação cresce.
Este módulo não possui perguntas. Marque como concluído.