I wrote some code to get data using pySerial
as below.
My class is depend on serial class which doesn't meet the "loose coupling" rule.
Should I use interface to decouple my class?
Thanks a lot for your instruction.
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()
I adjusted my code as recommended.
DI help to separate the serial process,and a factory method help to encapsulate the DI process.
Is there anything else I could do to meet the "loose coupling" rule?
Thanks for your help.
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()
I can think of 2 possible solutions
Do Dependency Injection, something likes this
def serial_connect(self, engine, serial_port, serial_baudrate)
Update for 1: I referred to http://en.wikipedia.org/wiki/Adapter_pattern which is commonly used when you want to separate the concrete implementation from the abstraction. Think of it as the travel plug adapter.
It is particularly useful for language like Java with strict interface and everything. In your case, because in Python we don't have "interface", you can simulate it by using an abstract 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
Then in ArduinoConnect
, you can check for the type
def __init__(self, serial_to_arduino):
if not isinstance(serial_to_arduino, AbstractAdapter):
raise("Wrong type")
This forces your serial_to_arduino
to extend AbstractAdapter
which enforces the implementation of all abstract methods hence an adapter.
This might not be the most "pythonic" way to do things, but from OOP point of view, you can do it that way to have the highest level of loose coupling (In my opinion)
P/s: Actually, I think the correct pattern in this case should be Strategy, both of them are pretty similar in term of implementation but they are meant for different purposes. You can read more about some patterns like Strategy, Proxy, Command, Mediator which are often used to achieve loose coupling