Muito interessante. Obrigado. Poderia dar algum exemplo nesse contexto que mostrei no código?

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.

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
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.