il mio modello di software ha una sorta di dipendenza ciclica

0

Ho bisogno di una raccomandazione sul mio modello di software.

Penso che non sia così buono, dal momento che esiste una sorta di dipendenza ciclica.

Ho un pacchetto OSGI in framework di applicazioni Kura , qui ci sono le classi:

  • Classe principale: il punto di ingresso del pacchetto
  • TwoWaySerialComm: per comunicazioni seriali con un dispositivo Arduino
  • SerialReader: responsabile della lettura dalla porta seriale dei dati provenienti da Arduino e quindi invia i dati ricevuti al cloud utilizzando il servizio DataService di KURA.

    class Main {
        public static DataService m_dataService;//KURA service to send information to the cloud via MQTT  
    
        protected void activate(ComponentContext componentContext) {
        serialCom = new TwoWaySerialComm();//responsible for serial communication
          serialCom.connect("/dev/ttyUSB0"); 
        }
    }
    
    class TwoWaySerialComm {
        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
        }
    }
    
    public class SerialReader  implements SerialPortEventListener  {
        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:
            Main.m_dataService.publish();
        }
    }
    

È una cattiva modellazione, se sì come posso risolverlo?

    
posta sabrina2020 17.11.2015 - 22:04
fonte

2 risposte

2

Sì, l'eccessiva conoscenza di altre classi e il corrispondente accoppiamento stretto sono pessimi.

Buone notizie! È facilmente risolvibile con inversione di dipendenza .

Il difetto chiave è che SerialReader sa che Principale ha la sua dipendenza DataService . Non ha bisogno di sapere questo, e non dovrebbe. Invece dovrebbe essere costruito con un DataService . Questa è chiamata inversione di dipendenza o iniezione di dipendenza .

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(); 
    }
}

La stessa tecnica può essere applicata con ancora più eleganza su TwoWaySerialComm in quanto può dipendere dall'interfaccia SerialPortEventListener anziché da una classe specifica che la rende molto liberamente accoppiata.

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
    }
}

E Principale fa il suo lavoro che è, e dovrebbe essere sempre, limitato al cablaggio delle dipendenze e all'avvio del sistema.

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");
    }
}

Potresti notare che ho rinominato m_dataService in dataService . Il m _ è usato occasionalmente in C ++, ma è considerato cattivo stile in Java.

    
risposta data 18.11.2015 - 19:40
fonte
2

Questo sembra un design problematico. Se una classe non può reggersi da sola, diventa effettivamente parte di una classe meta-Frankenstein non intenzionale insieme alle sue dure dipendenze. In questo caso, Main , TwoWaySerialComm e SerialReader sono effettivamente una classe, forse MainTwoWaySerialCommSerialReader .

Posso vedere un paio di modi per aggirarlo.

Se Main richiede un riferimento a DataService , condividi tale riferimento come parametro su TwoWaySerialComm e infine SerialReader . Non esporlo come membro pubblico.

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();
    }
}

Ora, sia TwoWaySerialComm che SerialReader possono essere utilizzati in altri contesti. Non richiedono Main .

Un'altra opzione è quella di spingere la responsabilità per il DataService più vicino a dove è usato. Se è fattibile, SerialReader potrebbe "possederlo".

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();
    }
}
    
risposta data 18.11.2015 - 16:38
fonte

Leggi altre domande sui tag