我需要一个关于我的软件模型的建议。
我认为这不是很好,因为有某种循环依赖。
我在库拉应用框架下有一个OSGI包,下面是类:
这是个糟糕的模特儿,如果是这样的话,我该怎么办呢?
发布于 2015-11-18 18:40:22
是的,对其他类的过度了解和相应的紧密耦合是不好的。
好消息!依赖反转很容易解决这个问题。
关键的缺陷是SerialReader知道Main有它的DataService依赖项。它不需要知道这一点,也不应该知道,相反,它应该使用DataService构建。这被称为依赖反转或依赖注入。
SerialReader.java:
public final class SerialReader implements SerialPortEventListener {
private final DataService dataService;
public SerialReader(DataService dataService) {
this.dataService = dataService;
}
public void serialEvent(SerialPortEvent arg0) {
//code for serial port reading omitted
//the data obtained from the serial is sent to the
//cloud via MQTT using the KURA service DataService as the following:
dataService.publish();
}
}同样的技术可以在TwoWaySerialComm上得到更多的应用,因为它可以依赖于SerialPortEventListener接口,而不是特定的类,使得它非常松散地耦合。
TwoWaySerialComm.java
final class TwoWaySerialComm {
private final SerialPortEventListener serialPort;
TwoWaySerialComm(SerialPortEventListener serialPort) {
this.serialPort = serialPort;
}
void connect(String portName) {
//code omitted
in = serialPort.getInputStream();
//add event listener to read data from the serial port
serialPort.addEventListener(new SerialReader(in));
//code omitted
}
}并且主服务器完成了它的工作,这是并且应该一直被限制在连接依赖项和启动系统上。
Main.java:
final class Main {
//KURA service to send information to the cloud via MQTT
public static final DataService dataService;
protected void activate(ComponentContext componentContext) {
SerialReader serialReader = new SerialReader(dataService);
TwoWaySerialComm serialCom = new TwoWaySerialComm(serialReader);//responsible for serial communication
serialCom.connect("/dev/ttyUSB0");
}
}您可能会注意到,我已将m_dataService重命名为dataService。m_偶尔在C++中使用,但在C++中被认为是糟糕的样式。
发布于 2015-11-18 15:38:30
这似乎是一个有问题的设计。如果一个类不能独立存在,它实际上成为意外的类的一部分,以及它的硬依赖关系。在这种情况下,Main、TwoWaySerialComm和SerialReader实际上是一个类,可能是MainTwoWaySerialCommSerialReader。
我能看到几种绕过它的方法。
如果Main需要对DataService的引用,则将该引用共享为TwoWaySerialComm的参数,并最终作为SerialReader的参数。不要把它暴露为公众成员。
class Main {
private static DataService m_dataService;
protected void activate(ComponentContext componentContext) {
serialCom = new TwoWaySerialComm();
serialCom.connect("/dev/ttyUSB0", m_dataService);
}
}
class TwoWaySerialComm{
void connect (String portName, DataService service) {
in = serialPort.getInputStream();
serialPort.addEventListener(new SerialReader(in, service));
}
}
public class SerialReader implements SerialPortEventListener {
private Stream in;
private DataService service;
SerialReader (Stream in, DataService service) {
this.in = in;
this.service = service;
}
public void serialEvent(SerialPortEvent arg0) {
this.service.publish();
}
}现在,TwoWaySerialComm和SerialReader都可以在其他上下文中使用。他们不需要Main。
另一种选择是将DataService的责任推到更接近使用它的位置。如果可行的话,SerialReader可以“拥有”它。
class Main {
protected void activate(ComponentContext componentContext) {
serialCom = new TwoWaySerialComm();
serialCom.connect("/dev/ttyUSB0");
}
}
class TwoWaySerialComm{
void connect (String portName) {
in = serialPort.getInputStream();
serialPort.addEventListener(new SerialReader(in));
}
}
public class SerialReader implements SerialPortEventListener {
private Stream in;
private DataService service;
SerialReader (Stream in) {
this.in = in;
// Not sure if this is possible.
// If it is, it reduces the need to juggle the DataService
// reference between classes.
this.service = ResolveDataServiceSomehow();
}
public void serialEvent(SerialPortEvent arg0) {
this.service.publish();
}
}https://softwareengineering.stackexchange.com/questions/302853
复制相似问题