Search code examples
pythoninheritancedesign-patternsdjango-rest-frameworkmultiple-inheritance

Is there an alternative to using multiple inheritance in python in my case?


Let's say there are several classes

class Order:
  def create_basic_order(self):
    pass
    # something here

  def create_difficult_order(self):
    pass
    # something here  


class Point:
  def create_full_point(self):
    pass
    # something here

  def create_limited_point(self):
    pass
    # something here

And the client sends a request with a specific command in json format. For example {"command": "create_limited_point"}.

And the server should execute the appropriate command. In this case: Point().create_limited_point().

All commands are different. The most obvious way to do it without the 'if construct' is like this:

class App(Order, Point):
  pass
  # maybe something here

# Code to handle client request
command = 'create_limited_point'
a = App()
method_to_call = getattr(a, command)
method_to_call()

The class App collects all the methods that the client can use. Is this a good way to accomplish the task at hand?


Solution

  • I'm not sure what your app is but you are right, the solution you suggest is terrible. And if you can, you should probably refactor this code a bit. Multiple inheritance is usually a bad idea.

    Something like that might work better for you.

    import abc
    from typing import Dict
    
    
    class EventHandler(metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def handle(self):
            pass
    
    
    class BasicOrderHandler(EventHandler):
        def handle(self):
            pass
    
    
    class DifficultOrderHandler(EventHandler):
        def handle(self):
            pass
    
    
    class FullPointHandler(EventHandler):
        def handle(self):
            pass
    
    
    class LimitedPointHandler(EventHandler):
        def handle(self):
            pass
    
    
    class App:
        commands_handlers_mapper: Dict[str, EventHandler] = {
            'create_limited_point': LimitedPointHandler,
            'create_full_point': FullPointHandler,
            'create_difficult_order': BasicOrderHandler,
            'create_basic_order': BasicOrderHandler
        }
    
        def execute_command(self, command: str) -> None:
            handler = self.commands_handlers_mapper[command]
            handler.handle()
    
    
    command = 'create_limited_point'
    a = App()
    a.execute_command(command)
    

    Bonus points for putting those commands into constants, which is just a class attribute, enums or just string assigned to a variable.