1

I have a class representing a Request. I have a set of very specific requests such as "I-95", "P-22", etc. which perform distinct functions and are called by a controller class. What is the best way to do this so that one could add more requests easily down the road?

I have something like this at the moment:

class Requests:
    def __init__(self):
            self.types = [
                    'I-95',
                    'P-22',
                    ...
            ]

    def generate_request(self,type, Data):
            # Here I would call the appropriate case for the type, e.g. P-22

A Request case would be in its own separate file and look like this:

class P-22:
    # Members
    def __init__(self, Data):
        # Set data members
    def request(self):
        # Submit request

And I would be able to create a request in the controller

f = Requests()
f.generate_request('RC75')

I'm striving for something that's as clean and easily extendable as possible. Thank you!

Connor Spangler
  • 805
  • 2
  • 12
  • 29
  • What do you dislike about your current solution? – rrauenza Jun 10 '16 at 19:19
  • Well for starters I'd like to implement something akin to an enum with the list of request types. A key value pair dictionary perhaps with the name of the request as the key and a pointer to its functions as its value. – Connor Spangler Jun 10 '16 at 19:23

1 Answers1

8

Try something like:

class BaseRequest:
    name = None


class FooRequest(BaseRequest):
    name = 'I-95'

    def response(self):
        return "foo"


class BarRequest(BaseRequest):
    name = 'P-22'

    def response(self):
        return "bar"


class RequestManager:

    def __init__(self):
        self.requests = {
            FooRequest.name: FooRequest,
            BarRequest.name: BarRequest
        }

    def generate_request(self, name):
        if name in self.requests:
            return self.requests[name]()

    def register_request(self, request_class):
        assert issubclass(request_class, BaseRequest), \
            'Request class not a subclass of BaseRequest'
        assert hasattr('name', request_class) and isinstance(request_class.name, str), \
            'Request name not correctly configured'
        self.requests[request_class.name] = request_class

And then:

manager = RequestManager()
request = manager.generate_request('I-95')
if request is not None:
    print(request.response()) # "foo"

And for registering new requests:

class NewRequest(BaseRequest):
    name = 'N-1'

    def response(self):
        return "new"

manager = RequestManager()
manager.register_request(NewRequest)
request = manager.generate_request('N-1')
if request is not None:
    print(request.response()) # "new"

I personally think this is better done using a Singleton-pattern for the RequestManager (untested!):

class RequestManager:

    instance = None

    class __RequestManager:
        requests = {
            FooRequest.name: FooRequest,
            BarRequest.name: BarRequest
        }

        def generate_request(self, name):
            if name in self.requests:
                return self.requests[name]()

        def register_request(self, request_class):
            assert issubclass(request_class, BaseRequest), \
                'Request class not a subclass of BaseRequest'
            assert hasattr('name', request_class) and isinstance(request_class.name, str), \
                'Request name not correctly configured'
            self.requests[request_class.name] = request_class

    def __new__(cls):
        if not cls.instance:
            cls.instance = cls.__RequestManager()
        return cls.instance

    @staticmethod
    def getInstance():
        return RequestManager()

This creates a statically accessible RequestManager instance:

manager = RequestManager.getInstance()
# Rest same as before, register some requests, etc.

manager2 = RequestManager.getInstance() # This is actually the same manager ie. the same instance!

manager and manager2 share the same requests dictionary, so updates via one of them applies to both (technically speaking to the same manager, because you retrieve the same instance twice)

Elwin Arens
  • 1,542
  • 10
  • 21