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 MonitoringDecorator referencia um objeto do tipo Monitoring, podendo este ser tanto um SimpleMonitoring quanto um MonitoringDecorator. A classe abstrata BinaryOperatorDecorator referencia um segundo objeto do tipo Monitoring e é quem torna possível compor diversos objetos do tipo Monitoring indefinidamente, encapsulando conjuntos de monitoramentos em operações binárias. Ambas as classes também definem a operação evaluateCondition, que verifica o resultado da condição para o objeto do tipo Monitoring referenciado. As subclasses concretas AndDecorator e OrDecorator verificam o resultado das respectivas operações binárias entre os resultados de evaluateCondition para os objeto referenciados por MonitoringDecorator e por BinaryOperatorDecorator.
package decorator;
public interface Monitoring {
public boolean evaluateCondition();
}
package decorator;
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 decorator;
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 decorator;
public class LessThanMonitoring extends SimpleMonitoring {
// No construtor, as informações necessárias para o construtor da classe abstrata SimpleMonitoring
// devem ser recebidos
public LessThanMonitoring(Sensor sensor, float value) {
super(sensor, value);
}
public boolean evaluateCondition() {
return super.getSensorValue() < super.getValue();
}
}
package decorator;
public class GreaterThanMonitoring extends SimpleMonitoring {
// No construtor, as informações necessárias para o construtor da classe abstrata SimpleMonitoring
// devem ser recebidos
public GreaterThanMonitoring(Sensor sensor, float value) {
super(sensor, value);
}
public boolean evaluateCondition() {
return super.getSensorValue() > super.getValue();
}
}
package decorator;
public class EqualsToMonitoring extends SimpleMonitoring {
// No construtor, as informações necessárias para o construtor da classe abstrata SimpleMonitoring
// devem ser recebidos
public EqualsToMonitoring(Sensor sensor, float value) {
super(sensor, value);
}
public boolean evaluateCondition() {
return super.getSensorValue() == super.getValue();
}
}
package decorator;
public abstract class MonitoringDecorator implements Monitoring{
// O componente encapsulado pelo Decorator, do tipo Monitoring
private final Monitoring component;
public MonitoringDecorator(Monitoring component) {
this.component = component;
}
public boolean evaluateCondition() {
return this.component.evaluateCondition();
}
}
package decorator;
public abstract class BinaryOperatorDecorator extends MonitoringDecorator {
// O segundo operando definido para a operação binária
private final Monitoring leftOperand;
// O construtor recebe os dois operandos, sendo um deles passado para a classe MonitoringDecorator
public BinaryOperatorDecorator(Monitoring component, Monitoring leftOperand) {
super(component);
this.leftOperand = leftOperand;
}
public boolean evaluateCondition() {
return this.leftOperand.evaluateCondition();
}
public boolean evaluateOperandCondition() {
return super.evaluateCondition();
}
}
package decorator;
public class AndDecorator extends BinaryOperatorDecorator {
public AndDecorator(Monitoring operand, Monitoring leftOperand) {
super(operand, leftOperand);
}
public boolean evaluateCondition() {
return super.evaluateCondition() && super.evaluateOperandCondition();
}
}
package decorator;
public class OrDecorator extends BinaryOperatorDecorator {
public OrDecorator(Monitoring operand, Monitoring leftOperand) {
super(operand, leftOperand);
}
public boolean evaluateCondition() {
return super.evaluateCondition() || super.evaluateOperandCondition();
}
}
package decorator;
public class Main {
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);
// Dois decorators são criados para encapsular os monitoramentos simples em operações binárias
AndDecorator pressureAndWaterLevelMonitoring = new AndDecorator(pressureOver60, waterLevelBelow40);
OrDecorator temperatureRangeMonitoring = new OrDecorator(temperatureOver50, temperatureBelow10);
// Um decorator é criado para encapsular os dois decorators criados em uma única operação binária
OrDecorator mainMonitoring = new OrDecorator(pressureAndWaterLevelMonitoring, temperatureRangeMonitoring);
// Sensores identificam os valores:
pressure.setValue(50);
waterLevel.setValue(45);
temperature.setValue(49);
if(mainMonitoring.evaluateCondition()) {
System.out.println("Uma falha foi detectada!");
} else {
System.out.println("Nenhuma falha foi detectada.");
}
}
}