Подключиться к сервису двумя или более способами, делегировать выполнение метода в Python - PullRequest
0 голосов
/ 15 мая 2018

Я натолкнулся на интригующий случай, когда мне приходится подключаться к веб-сервису двумя различными способами, основываясь на предпочтениях потребителей.Для целей этого вопроса я бы предпочел не упоминать какие-либо продукты, скажем, это веб-сервис под названием «Сервис», к которому может обращаться RestAPI и брокер сообщений.

Мой упрощенный код выглядит следующим образом:

import configparser
import os

from MyApp.Exceptions import WrongModeException

class Service(object):
    cfg_file = 'path/to/cfg.ini'
    config = configparser.ConfigParser()
    config.read(cfg_file)

    @staticmethod
    def generate_password():
        return 'ToPsEcReTp4ssw0rD'

class ServiceAPI(Service):
    def __init__(self):
        self.connection = APIConnect(self.config.some_param)

    def do_stuff(self, a):
        self.connection.do_stuff(a=a)

class ServiceMessageBroker(Service):
    def __init__(self):
        self.connection = MessageBrokerConnect(self.config.some_param)

    def do_stuff(self, a):
        self.connection.do_stuff(a=a)

class ServiceWrapper(Service):
    def __init__(self):
        mode = self.config.get(option='mode')

        if mode == 'Message Broker':
            self.service = ServiceMessageBroker()
        elif mode == 'API':
            self.service = ServiceAPI()
        else:
            raise WrongModeException
            os.sys.exit(1)

    def do_stuff(self, **kwargs):
        self.service.do_stuff(**kwargs)


if __name__ == '__main__':
    s = ServiceWrapper()
    s.do_stuff(a='blabla')

Есть ли лучший и более чистый способ сделать это?Я думал о сопоставлении соответствующих функций в словаре, а затем использовал его для выполнения, но мне это кажется ужасно уродливым.

Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 15 мая 2018

Не можете ли вы превратить упаковщик в фабрику?

def create_service():
    mode = ...
    service_classes = {'Message Broker': ServiceMessageBroker,
                       'API': ServiceAPI }
    try:
        service_cls = service_classes[mode]
    except KeyError:
        raise WrongModeException

    service_obj = service_cls()
    return service_obj
0 голосов
/ 16 мая 2018

Предположительно, еще более питонное и чистое решение, которое предложил мой друг, адаптированное для включения ваших предложений:

import configparser
import os

from MyApp.Exceptions import WrongModeException

class AbstractService(object):
    cfg_file = 'path/to/cfg.ini'
    config = configparser.ConfigParser()
    config.read(cfg_file)

    def do_stuff(self, a):
        raise NotImplementedError


class ServiceAPI(AbstractService):
    def __init__(self):
        self.connection = APIConnect(self.config.some_param)

    def do_stuff(self, a):
        self.connection.do_stuff(a=a)

class ServiceMessageBroker(AbstractService):
    def __init__(self):
        self.connection = MessageBrokerConnect(self.config.some_param)

    def do_stuff(self, a):
        self.connection.do_stuff(a=a)

class Service(object):

    def __new__(cls, *args, **kwargs):
        mode = AbstractService.config.get(option='mode')

        class_mapping = {
            'Message Broker': ServiceMessageBroker,
            'API': ServiceAPI
        }

        try:
            chosen_class = cls.class_mapping[mode]
        except KeyError:
            raise WrongeModeException

        return super(Service, cls).__new__(chosen_class, *args, **kwargs)


if __name__ == '__main__':
    s = ServiceWrapper()
    s.__init__()
    s.do_stuff(a='blabla')
0 голосов
/ 15 мая 2018

Использование словаря в качестве диспетчера функций, на мой взгляд, чисто и легко адаптируется. Я бы предпочел это конструкции if / elif / else, особенно если это способствует удобочитаемости.

Это, например, мне кажется более читабельным:

class ServiceWrapper(Service):
    def __init__(self):
        mode = self.config.get(option='mode')

        d = {'Message Broker': ServiceMessageBroker,
             'API': ServiceAPI}

        if mode not in d:
            raise WrongModeException
            os.sys.exit(1)

        self.service = d[mode]()

    def do_stuff(self, **kwargs):
        self.service.do_stuff(**kwargs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...