2
\$\begingroup\$

I'm practicing oop concepts these days. To figure it out I tried the below problem.

There is a sensor monitoring system. It is a simple system that prints a value, whenever a sensor has picked a value.

I tried to solve this problem according to oop and SOLID principals.

So I created an interface SensorListener

interface SensorListener{
    public void onValueUpdated(SensorTypes type, double value);
}

Then I created a Sensor class

public class Sensor {

    private int value;
    private SensorTypes types;
    private SensorListener sensorListener;

    public Sensor(SensorTypes types) {
        this.types = types;
    }

    public void setValue(int value) {
        this.value = value;
        sensorListener.onValueUpdated(types, value);
    }

    public void registerListener(SensorListener sensorListener) {
        this.sensorListener = sensorListener;
    }

}

For sensor types the enum is as below

public enum SensorTypes {
    TEMPERATURE, PH, HUMIDITY;
}

For the monitoring purpose I created a class SensorMonitor that implements SensorListener`

public class SensorMonitor implements SensorListener {

    @Override
    public void onValueUpdated(SensorTypes type, double value) {
        System.out.println("Sensor Name: " + type + ", Measure: " + value);
    }

}

Finally in the main method I mocked the sensor updated using a Thread,

public static void main(String[] args) {

    SensorMonitor sensorMonitor = new SensorMonitor();
    Sensor temperature = new Sensor(SensorTypes.TEMPERATURE);
    temperature.registerListener(sensorMonitor);
    Sensor humidity = new Sensor(SensorTypes.HUMIDITY);
    humidity.registerListener(sensorMonitor);
    Sensor pH = new Sensor(SensorTypes.PH);
    pH.registerListener(sensorMonitor);
    Thread thread = new Thread(() -> {
        int i = 0;
        while (true) {
            try {
                temperature.setValue(i++);
                Thread.sleep(3000);
                humidity.setValue(i++);
                Thread.sleep(3000);
                pH.setValue(i++);
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                System.out.println("thread interrupted");
            }
        }
    });

    thread.start();

}

In this way program successfully works and prints the output in 3 second intervals.

Sensor Name: TEMPERATURE, Measure: 0.0

Sensor Name: HUMIDITY, Measure: 1.0

Sensor Name: PH, Measure: 2.0

I'm satisfied with the behavior because it does what it says. But I'm not sure whether this a correct oop way of implementing interfaces and whether up to which context is this application scalable.

For example as the SensorMonitor how can it know the details of currently operating sensors, and what sensors are in the monitoring process?

Can someone point out what are the pros and cons in my approach.

Is this conforms to SOLID principals?

I appreciate a more concise approach for this problem.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Very good code, nicely done.

As for your questions:

For example as the SensorMonitor how can it know the details of currently operating sensors, and what sensors are in the monitoring process?

It does not.

You have modeled a clear association direction, which is: the sensor knows its listener, the listener does not know the sensor.

If you need such an association, you'll have to turn the dependency around (which is OK, as there's still no dependency loop, because you implement the listener as an interface):

+------------------+                 +-----------------+
| Monitor          |--(implements)-->| Listener        |
+------------------+                 +-----------------+
          |                                 ^
          |        +-----------------+      |
          +------->| Sensor          |------+
        (knows)    +-----------------+   (knows)

This way, you'd give the Monitor a "registerSensor(Sensor)" method, which records the Sensor internally in the monitor, and adds the monitor as a listener to the sensor.

\$\endgroup\$
3
  • \$\begingroup\$ Thank you for the review. So I'll need to add the sensor to the monitor if I need more information. \$\endgroup\$ Commented Jun 11, 2021 at 6:19
  • 1
    \$\begingroup\$ Yes. And as long as you don't introduce dependency loops, this is fine. \$\endgroup\$
    – mtj
    Commented Jun 11, 2021 at 6:21
  • \$\begingroup\$ Thank you now I got it. \$\endgroup\$ Commented Jun 11, 2021 at 6:25
1
\$\begingroup\$

some side notes i want to add a reference implementation from Java,

these Observable (Sensor) has the full ability to handle Observers (SensorListener) properly:

void addObserver(Observer o) 
int countObservers() 
void deleteObserver(Observer o) 
void deleteObservers()

i am sure you would add these methods as well as your code grows

and the listener interface Observer.update(Observable o, Object arg) with the parameters Parameters:

o - the observable object.

arg - an argument passed to the notifyObservers method.

these might be a hint on your question towards: For example as the SensorMonitor how can it know the details of currently operating sensors?

a explicit example could be the the android View.OnTouchListener where exactly this behaviour is implemented:

public abstract boolean onTouch (View v, MotionEvent event)

Called when a touch event is dispatched to a view. 
This allows listeners to get a chance to respond before the target view.

Parameters
 - v View: The view the touch event has been dispatched to.
 - event MotionEvent: The MotionEvent object containing full information about the event.

here you get the information on the observed object, namely the view where the touch Event happened AND the kind of event (touchEvent) that happened.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.