Executando verificação de segurança...
Em resposta a [Não disponível]
1

Os paradigmas de Orientação a Objetos (OO) e Programação Funcional (FP), oferecem soluções eficazes para lidar com lógicas condicionais complexas e evitar longas cadeias de if e elif.

No paradigma OO, utilizamos o polimorfismo para lidar com isso. Através da herança ou composição, objetos de diferentes classes podem ser tratados de forma unificada, permitindo que um mesmo nome de método (como value(), por exemplo) tenha comportamentos distintos dependendo da classe do objeto. Assim, ao invés de checar manualmente com if e elif qual ação executar, o próprio objeto, baseado em sua classe, sabe qual ação tomar.

Já no paradigma FP, técnicas como composição de funções e curring nos permitem criar sequências de chamadas de funções de maneira elegante e concisa. Ao invés de usar condicionais para decidir qual função chamar, podemos simplesmente invocar a função apropriada diretamente, muitas vezes utilizando dicionários para mapear nomes de ações a funções específicas, sendo o exemplo apresentado uma forma rudimentar de fazer isso.

Em termos amplos, tanto o polimorfismo no paradigma OO quanto a composição e o curring no paradigma FP são abordagens valiosas que nos ajudam a simplificar e organizar nosso código, tornando-o mais legível, manutenível e extensível.

Python é uma linguagem multiparadigma, o que significa que ela suporta parcialmente tanto a Programação Orientada a Objetos quanto a Programação Funcional. A filosofia do Python enfatiza a legibilidade e a "forma Pythonica" de fazer as coisas. Ambas as abordagens, OO e FP, podem ser muito "Pythonicas" quando implementadas corretamente. Seja utilizando classes, herança e polimorfismo, ou utilizando funções de primeira classe, lambdas e curring, podemos escrever código elegante, conciso e eficiente em Python que não contenham nenhum if/else.

Carregando publicação patrocinada...
1
3

Ambos os exemplos, seja utilizando uma abordagem orientada a objetos (OO) ou uma abordagem funcional (FP), de fato, recorrem a uma técnica similar: a ideia de usar o nome dinamicamente para obter uma referência à classe ou função correta. Isso é uma "gambiarra", mas também é uma demonstração do poder e flexibilidade que linguagens como Python oferecem.

No entanto, o que realmente importa aqui é o princípio subjacente que estamos tentando destacar: a ideia de abstrair a lógica condicional, de modo a tornar o código mais limpo, modular e extensível.

Quando falamos de abstrair lógicas condicionais, não estamos necessariamente falando sobre eliminá-las completamente. Em vez disso, estamos falando sobre movê-las para lugares onde elas fazem mais sentido ou são mais gerenciáveis. Em muitos casos, esta abstração resulta em um design mais limpo e em um código mais fácil de manter.

No entanto, é fundamental reconhecer que, em algum ponto, alguma forma de decisão ou lógica condicional ainda precisará existir. Seja em um dicionário que mapeia chaves a valores, em uma série de if-elif-else, ou em algum outro mecanismo - veja sobre branchless programming - essa lógica estará lá. O que estamos fazendo com essas abordagens é encapsulando, organizando ou distribuindo essa lógica de uma maneira que faça sentido para o problema e que mantenha o código limpo e manutenível.

2

Claro, vamos lá:
Primeiramentante tenha em mente que estes exemplos, embora simples e didáticos, são apenas ilustrativos e servem para demonstrar os conceitos fundamentais de diferentes paradigmas de programação. Na prática real, onde os problemas são muito mais complexos e multifacetados, os benefícios destas abordagens tornam-se mais evidentes.

OO

class Action:
  def value(self):
      return None

class CreateAction():
  def value(self):
      return 1

class ReadAction():
  def value(self):
      return 2

class UpdateAction():
  def value(self):
      return 3

class DeleteAction():
  def value(self):
      return 4

def receiveActionOO(action):
  className = f"{action.capitalize()}Action"
  actionClass = globals().get(className, Action)()
  return actionClass.value()

FP

def create_action():
  return 1

def read_action():
  return 2

def update_action():
  return 3

def delete_action():
  return 4

def default_action():
  return None

def receiveActionFP(action):
  function_name = f"{action}_action"
  action_func = globals().get(function_name, default_action)
  return action_func()
action = 'update'
value_long = recieveActionLong(action)
value_short = recieveActionsShort(action)
value_OO = receiveActionOO(action)
value_FP = receiveActionFP(action)

print('Valor da ação longa: ', value_long) # 3
print('Valor da ação curta: ', value_short) # 3
print('Valor da ação OO: ', value_OO) # 3
print('Valor da ação FP:', value_FP) # 3
3

Eu acho que só vale a pena fazer isso se as classes fizerem algum processamento mais complexo. Se for pra retornar sempre o mesmo valor fixo, isso aí é um canhão pra matar mosca.

É bom saber que existe essa alternativa, claro. Mas sei lá, eu prefiro começar simples, e complicar somente se houver necessidade.