1
resposta

Não entendi o uso do Abstract Method

Porque usar o abstract method e não uma outra classe?

1 resposta

Para ficar mais claro o uso do Abstract Method, posso te dar um exemplo onde ele é útil:

Vamos supor que você trabalhe um serviço de streaming como Globoplay, onde você terá no sistema uma classe chamada Globoplay para representar a assinatura

class Globoplay:
    def get_valor(self):
        return 20.0

Mas no Globoplay existem os combos, então você também pode assinar Globoplay + Disney, portanto no sistema você precisará criar uma classe assim:

class GloboplayComDisney:
    def get_valor(self):
        return Globoplay.get_valor() + 25.0

No Globoplay também existe o combo Globoplay + Disney + Deezer, portanto no sistema você precisará criar uma classe assim:

class GloboplayComDisneyComDeezer:
    def get_valor(self):
        return GloboplayComDisney.get_valor() + 15.0

Mas também é possível comprarmos os combos de Disney + Deezer, ou Globoplay + Deezer... Ou seja, as combinações de produtos são quase infinitas, isso acaba se tornando um problema para o nosso sistema, teremos um número muito grande de classes, e esses combos ficarão muito difíceis de manter, a forma como estamos fazendo o design da nossa aplicação vai prejudicar a manutenção, e nós podemos utilizar Abstract Method para melhor modelar nossa aplicação, dessa forma:

Teríamos uma classe abstrata:

from abc import ABC, abstractmethod

class Produto(ABC):
    def __init__(self, outro_produto=None):
        self.outro_produto = outro_produto

    # Método abstrato que deve ser implementado pelas subclasses
    @abstractmethod
    def get_valor(self):
        pass

    # Método para obter o valor de outro produto
    def get_valor_do_outro_produto(self):
        if self.outro_produto is not None:
            return self.outro_produto.get_valor()
        return 0

E teríamos uma classe por produto, onde todas as classes herdariam da classe abstrata:

class Globoplay(Produto):
    def __init__(self, outro_produto=None):
        super().__init__(outro_produto)

    def get_valor(self):
        return 20.0 + self.get_valor_do_outro_produto()
class Disney(Produto):
    def __init__(self, outro_produto=None):
        super().__init__(outro_produto)

    def get_valor(self):
        return 25.0 + self.get_valor_do_outro_produto()
class Deezer(Produto):
    def __init__(self, outro_produto=None):
        super().__init__(outro_produto)

    def get_valor(self):
        return 15.0 + self.get_valor_do_outro_produto()

Assim, nossa classe principal ficaria dessa forma:

globoplay = Globoplay()
globoplay_com_disney = Globoplay(Disney())
globoplay_com_disney_com_deezer = Globoplay(Disney(Deezer()))

Nós não temos mais 1 classe para cada combo, nós temos 1 classe para cada produto, onde 1 produto pode compor-se com outro, um produto pode receber outro no construtor, a classe abstrata e o nosso abstract method garantem de fazer os cálculos dos valores pois todos os produtos implementam o método de get_valor

Essa estratégia se chama Decorator, um design pattern que utiliza Abstract Method para resolver problema onde classes podem ser compostas por elas mesmas Insira aqui a descrição dessa imagem para ajudar na acessibilidade