Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以两种或多种方式连接到服务,在Python中委托方法执行_Python_Python 3.x_Oop_Object_Inheritance - Fatal编程技术网

以两种或多种方式连接到服务,在Python中委托方法执行

以两种或多种方式连接到服务,在Python中委托方法执行,python,python-3.x,oop,object,inheritance,Python,Python 3.x,Oop,Object,Inheritance,我遇到了一个有趣的例子,根据消费者的偏好,我必须以两种不同的方式连接到web服务。出于这个问题的目的,我不想提及任何产品,假设它是一个称为“服务”的web服务,可以由RestAPI和MessageBroker访问 我的简化代码如下所示: import configparser import os from MyApp.Exceptions import WrongModeException class Service(object): cfg_file = 'path/to/cfg.

我遇到了一个有趣的例子,根据消费者的偏好,我必须以两种不同的方式连接到web服务。出于这个问题的目的,我不想提及任何产品,假设它是一个称为“服务”的web服务,可以由RestAPI和MessageBroker访问

我的简化代码如下所示:

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')
有更好更干净的方法吗?我曾考虑在字典中映射适当的函数,然后使用它来执行,但对我来说,这似乎太难看了


提前谢谢

在我看来,使用字典作为函数分派器是干净的、适应性强的。我更喜欢使用
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)

你不能把包装纸变成工厂吗

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

我的一位朋友提出了一个更具pythonic和clean的解决方案,其中还包括您的建议:

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')

这绝对是一个选择。但由于其他原因,我还是希望它是一门课。谢谢然后你仍然需要显式地转发每个调用,或者做一些更复杂的事情,比如重写call方法——这不是你应该轻易做的事情。我承认,看起来更干净