Decorator

Vantagens

Desvantagens

Exemplos

Exemplo #1

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.

Diagrama de Classe

Exemplo #1 - Diagrama

Participantes

  • Component (Monitoring): Define uma interface para objetos que podem ter responsabilidades acrescentadas dinamicamente.
  • ConcreteComponent (SimpleMonitoring, LessThanMonitoring, GreaterThanMonitoring, EqualsToMonitoring): Define um objeto que pode ser decorado com novas responsabilidades.
  • Decorator (MonitoringDecorator, BinaryOperatorDecorator): Define uma interface para objetos que podem acrescentar novas responsabilidades e armazena objetos do tipo Component.
  • ConcreteDecorator (AndDecorator, OrDecorator): Define um objeto que acrescenta uma responsabilidade específica para um objeto do tipo Component.

Código

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

    }
}
Clique aqui para fazer o download do código completo de implementação deste Design Pattern.

Padrões Relacionados

Este Padrão pode ser usado para resolver os seguintes problemas: