在 python 中做 "loose coupling" 的正确方法是什么?

What is the right way to do "loose coupling" in python?

我写了一些代码来使用 pySerial 获取数据,如下所示。
我的 class 依赖于不符合 "loose coupling" 规则的序列号 class。
我应该使用接口来解耦我的 class 吗?
非常感谢您的指导。

import serial

class ArduinoConnect:  

    def __init__(self):
        pass

    def serial_connect(self, serial_port, serial_baudrate):

        self._serial_port = serial_port
        try:
           self.ser = serial.Serial(
                port=self._serial_port,
                baudrate=serial_baudrate,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                bytesize=serial.EIGHTBITS,
            )
        except serial.serialutil.SerialException, e:
            print str(e)

    def serial_disconnect(self):
        self.ser.close()

    def get_quaternion(self, number_of_data=50):

        buff = []
        self.ser.write('q')
        self.ser.write(chr(number_of_data))
        for j in range(number_of_data):
            in_string = self.ser.readline()
            buff_line = in_string.split(",")
            buff_line.pop()
            buff_line = self.hex_to_quaternion(buff_line)
            buff.append(list(buff_line))
        return buff

    def hex_to_quaternion(self, list_of_hex=None):
        #......
        pass

arduino = ArduinoConnect()
arduino.serial_connect(serial_port="COM5", serial_baudrate=115200)
print arduino.get_quaternion()
arduino.serial_disconnect()

我按照建议调整了我的代码。
DI有助于分离串行过程,工厂方法有助于封装DI过程。
我还能做些什么来满足 "loose coupling" 规则吗?
感谢您的帮助。

import serial

class ArduinoConnect:
    def __init__(self, serial_to_arduino):
        self._serial_to_arduino = serial_to_arduino

    def get_quaternion(self, number_of_data=50):
        buff = []
        self._serial_to_arduino.write('q')
        self._serial_to_arduino.write(chr(number_of_data))
        for j in range(number_of_data):
            in_string = self._serial_to_arduino.readline()
            buff_line = in_string.split(",")
            buff_line.pop()
            buff_line = self.hex_to_quaternion(buff_line)
            buff.append(list(buff_line))
        return buff

    def hex_to_quaternion(self, list_of_hex):
        ......

    def __getattr__(self, attr):
        return getattr(self._serial_to_arduino, attr)


class SerialToArduino:
    def __init__(self):
        pass

    def serial_connect(self, serial_port="COM5", serial_baudrate=115200):
        self._serial_port = serial_port
        try:
            self.ser = serial.Serial(
                port=self._serial_port,
                baudrate=serial_baudrate,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                bytesize=serial.EIGHTBITS,
            )
        except serial.serialutil.SerialException, e:
            print str(e)

    def serial_disconnect(self):
        self.ser.close()

    def readline(self):
        return self.ser.readline()

    def write(self, data):
        self.ser.write(data=data)


def get_ArduinoConnect():
    'factory method'
    return ArduinoConnect(serial_to_arduino=SerialToArduino())


arduino = get_ArduinoConnect()
arduino.serial_connect(serial_port="COM5", serial_baudrate=115200)
print arduino.get_quaternion()
arduino.serial_disconnect()

我能想到 2 种可能的解决方案

  1. 实现一个 "adapter" 以向主要 class 公开方法并隐藏 Serial 的实现。这样你的 main class 就可以避免依赖于具体的 class Serial
  2. 做依赖注入,像这样

    def serial_connect(self, engine, serial_port, serial_baudrate)

1 的更新:我提到了 http://en.wikipedia.org/wiki/Adapter_pattern,当您想要将具体实现与抽象分开时,通常会使用它。将其视为旅行插头适配器。

对于像Java这样接口严格什么都有的语言特别有用。在你的情况下,因为在 Python 中我们没有 "interface",你可以使用抽象 class

来模拟它
class AbstractAdapter():
      def serial_connect(self, serial_port="COM5", serial_baudrate=115200):
          raise("Needs implementation")
      # do the same thing for the rest of the methods

然后在ArduinoConnect中,你可以检查类型

def __init__(self, serial_to_arduino):
    if not isinstance(serial_to_arduino, AbstractAdapter):
        raise("Wrong type")

这会强制您的 serial_to_arduino 扩展 AbstractAdapter,从而强制实施所有抽象方法,因此是适配器。

这可能不是最 "pythonic" 的做事方式,但从 OOP 的角度来看,您可以这样做以获得最高级别的松散耦合(在我看来)

P/s:实际上,我认为在这种情况下正确的模式应该是策略,它们在实现方面非常相似,但它们的目的不同。您可以阅读更多有关 Strategy、Proxy、Command、Mediator 等模式的更多信息,这些模式通常用于实现松散耦合