Composite

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

Diagrama de Classe

Exemplo #1 - Diagrama

Participantes

  • Component (Monitoring): Declara uma interface comum para todos os objetos da composição.
  • Leaf (SimpleMonitoring, LessThanMonitoring, GreaterThanMonitoring, EqualsToMonitoring): Define os objetos folha da composição, que não possuem filhos.
  • Composite (CompoundMonitoring, AndMonitoring, OrMonitoring): Define o comportamento dos componentes que possuem objetos filhos, além de formas de armazená-los e referenciá-los.
  • Client (Client): Objeto que manipula os objetos da composição a partir de uma referência para uma classe Component.

Código

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