2
respostas

Capítulo 5 - Desconto Extra aplicado uma única vez - Possível alternativa

Tenho esse código que eu fiz na aula 5:

class Orcamento(object):

    def __init__(self):

        self.__itens = []
        self.estado_atual = EmAprovacao()
        self.__desconto_extra = 0
        self.__applied_desconto_extra = False

    def aprova(self):

        self.estado_atual.aprova(self)

    def reprova(self):

        self.estado_atual.reprova(self)

    def finaliza(self):

        self.estado_atual.finaliza(self)

    def aplica_desconto_extra(self):

        self.estado_atual.aplica_desconto_extra(self)

    def adiciona_desconto_extra(self, desconto):

        if not self.__applied_desconto_extra:
            self.__desconto_extra += desconto
            self.__applied_desconto_extra = True
        else:
            raise Exception("Desconto extra já foi aplicado!")

    @property
    def valor(self):

        total = 0.0
        for item in self.__itens:
            total += item.valor
        return total - self.__desconto_extra

    def obter_itens(self):

        return tuple(self.__itens)

    @property
    def total_itens(self):

        return len(self.__itens)

    def adicionar_item(self, item):

        self.__itens.append(item)

class Item(object):

    def __init__(self, nome, valor):

        self.__nome = nome
        self.__valor = valor

    @property
    def valor(self):

        return self.__valor

    @property
    def nome(self):

        return self.__nome

if __name__ == '__main__':

    from orcamento import Item

    orcamento = Orcamento()
    orcamento.adicionar_item(Item("Item - 1", 100))
    orcamento.adicionar_item(Item("Item - 1", 50))
    orcamento.adicionar_item(Item("Item - 1", 400))

    print orcamento.valor

    orcamento.aplica_desconto_extra()
    print orcamento.valor
    orcamento.aplica_desconto_extra()
    print orcamento.valor

Na resolução original, a lógica de checagem da aplicação do desconto extra é feita na classe "Estado_de_um_orcamento" e nas suas classes filhas, e também a checagem é colocada duas vezes: uma na classe "Em_aprovacao" e outra em "Aprovado".

Na minha resolução, a lógica da checagem é colocada uma única vez no método "adiciona_desconto_extra" da classe "Orcamento".

O resultado saiu assim:

python2 orcamento.py


550.0
539.0
Traceback (most recent call last):
  File "orcamento.py", line 184, in <module>
    orcamento.aplica_desconto_extra()
  File "orcamento.py", line 123, in aplica_desconto_extra
    self.estado_atual.aplica_desconto_extra(self)
  File "orcamento.py", line 30, in aplica_desconto_extra
    orcamento.adiciona_desconto_extra(orcamento.valor * 0.02)
  File "orcamento.py", line 131, in adiciona_desconto_extra
    raise Exception("Desconto extra já foi aplicado!")
Exception: Desconto extra já foi aplicado!

Gostaria de um feedback do pessoal. Essa solução seria viável ao design pattern State que vimos? Ou a resolução original seria melhor em questão de manutenção de código e legibilidade?

EDITADO: Achei um erro na minha implementação. Se o estado mudar, o desconto não poderá ser aplicado referente aquele novo estado do orçamento, pois a flag de desconto_extra vai ser "True" sempre e não irá mudar. Desculpa o encômodo pessoal, irei corrigir ele!

2 respostas

Nova versão:

class Orcamento(object):

    def __init__(self):

        self.__itens = []
        self.estado_atual = EmAprovacao()
        self.__desconto_extra = 0
        self.__applied_desconto_extra = False

    def aprova(self):

        self.estado_atual.aprova(self)
        self.__applied_desconto_extra = False

    def reprova(self):

        self.estado_atual.reprova(self)

    def finaliza(self):

        self.estado_atual.finaliza(self)

    def aplica_desconto_extra(self):

        self.estado_atual.aplica_desconto_extra(self)

    def adiciona_desconto_extra(self, desconto):

        if not self.__applied_desconto_extra:
            self.__desconto_extra += desconto
            self.__applied_desconto_extra = True
        else:
            raise Exception("Desconto extra já foi aplicado!")

    @property
    def valor(self):

        total = 0.0
        for item in self.__itens:
            total += item.valor
        return total - self.__desconto_extra

    def obter_itens(self):

        return tuple(self.__itens)

    @property
    def total_itens(self):

        return len(self.__itens)

    def adicionar_item(self, item):

        self.__itens.append(item)

class Item(object):

    def __init__(self, nome, valor):

        self.__nome = nome
        self.__valor = valor

    @property
    def valor(self):

        return self.__valor

    @property
    def nome(self):

        return self.__nome

if __name__ == '__main__':

    from orcamento import Item

    orcamento = Orcamento()
    orcamento.adicionar_item(Item("Item - 1", 100))
    orcamento.adicionar_item(Item("Item - 1", 50))
    orcamento.adicionar_item(Item("Item - 1", 400))

    print orcamento.valor

    orcamento.aplica_desconto_extra()
    print orcamento.valor

    orcamento.aprova()
    orcamento.aplica_desconto_extra()
    print orcamento.valor

    orcamento.aplica_desconto_extra()
    print orcamento.valor

Cada vez que o estado mudar, a flag "self.__applied_desconto_extra" é resetada para False. Um teste foi feito e deu nisso:

python2 orcamento.py


550.0
539.0
512.05
Traceback (most recent call last):
  File "orcamento.py", line 188, in <module>
    orcamento.aplica_desconto_extra()
  File "orcamento.py", line 124, in aplica_desconto_extra
    self.estado_atual.aplica_desconto_extra(self)
  File "orcamento.py", line 49, in aplica_desconto_extra
    orcamento.adiciona_desconto_extra(orcamento.valor * 0.05)
  File "orcamento.py", line 132, in adiciona_desconto_extra
    raise Exception("Desconto extra já foi aplicado!")
Exception: Desconto extra já foi aplicado!

O que acham?

Olá, Carlos!

Excelente! Sua solução ficou muito boa. Como é a mesma lógica, colocar na classe Orcamento faz muito sentido.