Uma empresa realiza um serviço de monitoramento em equipamentos para detectar falhas antes que elas aconteçam. Sensores são instalados nos equipamentos para monitorar características como temperatura ou pressão, sendo esses dados enviados para o sistema da empresa. Entretanto, dependendo do equipamento e de sua complexidade, a detecção de falhas depende de condições lógicas complexas que envolvem muitas comparações nas leituras de diversos sensores. Por exemplo, dados os sensores X, Y e Z, uma condição para uma falha pode ser composta da seguinte forma:
((X > 5) OR (X < 20)) AND (Y = 100) AND ((Z < 5) OR (Z > 2))
Por isso, uma forma mais simples de compor essas condições deve ser implementada, tornando mais fácil definir um monitoramento que detecta uma falha. A interface Monitoring representa um monitoramento e define a operação evaluateCondition, que avalia a condição proposta pelo monitoramento, verificando se ocorreu uma falha. A classe abstrata SimpleMonitoring representa o monitoramento de um único sensor e armazena o valor usado na comparação, além de possuir uma referência para um objeto do tipo Sensor, que armazena o valor real da leitura de um sensor. As classes concretas LessThanMonitoring, GreaterThanMonitoring e EqualsToMonitoring representam os comparadores que serão aplicados ao executar a operação evaluateCondition para verificar se o valor lido pelos sensores está dentro da condição para uma falha. A classe abstrata CompoundMonitoring implementa a interfae Monitoring e referencia um conjunto de objetos do tipo Monitoring, podendo eles ser tanto do tipo SimpleMonitoring quanto CompoundMonitoring. As classes concretas AndMonitoring e OrMonitoring herdam de CompoundMonitoring e implementam, na operação evaluateCondition, os operadores AND e OR que são aplicados percorrendo o conjunto de objetos referenciados e executando as operações evaluateCondition de cada um.
package composite;
public interface Monitoring {
public abstract boolean evaluateCondition();
}
package composite;
public class Client {
public static void main(String[] args) {
// São instanciados os sensores de pressão, temperatura e nível da água
Sensor pressure = new Sensor();
Sensor temperature = new Sensor();
Sensor waterLevel = new Sensor();
// O monitoramento do exemplo será composto da seguinte condição:
// (pressure > 60 && waterLevel < 40) || (temperature > 50 || temperature < 10)
// Para cada operação lógica da condição, um monitoramento simples é criado.
GreaterThanMonitoring pressureOver60 = new GreaterThanMonitoring(pressure, 60);
LessThanMonitoring waterLevelBelow40 = new LessThanMonitoring(waterLevel, 40);
GreaterThanMonitoring temperatureOver50 = new GreaterThanMonitoring(temperature, 50);
LessThanMonitoring temperatureBelow10 = new LessThanMonitoring(temperature, 10);
// Um monitoramento composto com uma lista contendo dois monitoramentos
AndMonitoring pressureAndWaterLevelMonitoring = new AndMonitoring();
pressureAndWaterLevelMonitoring.addMonitoring(pressureOver60);
pressureAndWaterLevelMonitoring.addMonitoring(waterLevelBelow40);
// Um segundo monitoramento composto com uma lista contendo dois monitoramentos
OrMonitoring temperatureRangeMonitoring = new OrMonitoring();
temperatureRangeMonitoring.addMonitoring(temperatureOver50);
temperatureRangeMonitoring.addMonitoring(temperatureBelow10);
// O monitoramento principal contem os dois monitoramentos compostos anteriores
OrMonitoring mainMonitoring = new OrMonitoring();
mainMonitoring.addMonitoring(pressureAndWaterLevelMonitoring);
mainMonitoring.addMonitoring(temperatureRangeMonitoring);
// Sensores identificam valores
pressure.setValue(50);
waterLevel.setValue(45);
temperature.setValue(55);
if(mainMonitoring.evaluateCondition()) {
System.out.println("Uma falha foi detectada!");
} else {
System.out.println("Nenhuma falha foi detectada.");
}
}
}
package composite;
public abstract class SimpleMonitoring implements Monitoring{
private final Sensor sensor; // Sensor monitorado
private final float value; // Valor usado na comparação
public SimpleMonitoring(Sensor sensor, float value) {
this.sensor = sensor;
this.value = value;
}
public float getValue() {
return this.value;
}
public float getSensorValue() {
return this.sensor.getValue();
}
}
package composite;
public class Sensor {
private float value; // valor lido pelo sensor
public float getValue() {
return this.value;
}
public void setValue(float value){
this.value = value;
}
}
package composite;
public class LessThanMonitoring extends SimpleMonitoring {
public LessThanMonitoring(Sensor sensor, float value) {
super(sensor, value);
}
public boolean evaluateCondition() {
return super.getSensorValue() < super.getValue();
}
}
package composite;
public class GreaterThanMonitoring extends SimpleMonitoring {
public GreaterThanMonitoring(Sensor sensor, float value) {
super(sensor, value);
}
public boolean evaluateCondition() {
return super.getSensorValue() > super.getValue();
}
}
package composite;
public class EqualsToMonitoring extends SimpleMonitoring {
public EqualsToMonitoring(Sensor sensor, float value) {
super(sensor, value);
}
public boolean evaluateCondition() {
return super.getSensorValue() == super.getValue();
}
}
package composite;
import java.util.ArrayList;
import java.util.List;
public abstract class CompoundMonitoring implements Monitoring {
// Grupo de monitoramentos da composição
private List monitorings = new ArrayList<>();
public void addMonitoring(Monitoring monitoring) {
this.monitorings.add(monitoring);
}
public List getMonitorings() {
return this.monitorings;
}
}
package composite;
public class AndMonitoring extends CompoundMonitoring {
public boolean evaluateCondition() {
for (Monitoring monitoring : super.getMonitorings()) {
if(!monitoring.evaluateCondition()) return false;
}
return true;
}
}
package composite;
public class OrMonitoring extends CompoundMonitoring {
public boolean evaluateCondition() {
for (Monitoring monitoring : super.getMonitorings()) {
if(monitoring.evaluateCondition()) return true;
}
return false;
}
}