abstract factory Pattern real world example in java

The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. Abstract Factory allows a client to use an abstract interface to create a set of related products without knowing (or caring) about the concrete products that are actually produced. In this way, the client is decoupled from any of the specifics of the concrete products. Let’s look at the class diagram to see how this all holds together.

We have two types of products to produce one is DeviationMode and the other is CorrectionStream.Below is the class hierarchy we will be working on.

Lets start with DeviationMode product

public abstract class DeviationMode {

public abstract float calculateMeanDeviation(float rawMetricValue,
float averageMetricValue);

public boolean compareMeanDeviation(float meanDevaition, int threshold) {
return meanDevaition > threshold;
}

}

public interface DeviationModeCorrectionFactory {

public CorrectionStream getCorrection(String mode);

}

public class DownStreamHigherMode extends DeviationMode{

public DeviationModeCorrectionFactory correctionFactory;

public DownStreamHigherMode(DeviationModeCorrectionFactory correctionFactory) {

this.correctionFactory=correctionFactory;
}

@Override
public float calculateMeanDeviation(float rawMetricValue,
float averageMetricValue) {

CorrectionStream correct=correctionFactory.getCorrection("HIGHER");
rawMetricValue=correct.correction((int)rawMetricValue);
if (rawMetricValue > averageMetricValue && averageMetricValue > 22) {
float meanDeviation = ((rawMetricValue - averageMetricValue) / averageMetricValue) * 100;
return meanDeviation;
}
return 0;
}

}
public class DownStreamLowerMode extends DeviationMode {

public DeviationModeCorrectionFactory correctionFactory;

public DownStreamLowerMode(DeviationModeCorrectionFactory correctionFactory) {

this.correctionFactory = correctionFactory;
}

@Override
public float calculateMeanDeviation(float rawMetricValue, float averageMetricValue) {
CorrectionStream correct = correctionFactory.getCorrection("LOWER");
rawMetricValue = correct.correction((int) rawMetricValue);

if (averageMetricValue > rawMetricValue && averageMetricValue > 15) {
float meanDeviation = ((averageMetricValue - rawMetricValue) / averageMetricValue) * 100;
return meanDeviation;
}
return 0;
}

}
public class UpstreamHigherMode extends DeviationMode {

public DeviationModeCorrectionFactory correctionFactory;

public UpstreamHigherMode(DeviationModeCorrectionFactory correctionFactory) {

this.correctionFactory = correctionFactory;
}

@Override
public float calculateMeanDeviation(float rawMetricValue, float averageMetricValue) {
CorrectionStream correct=correctionFactory.getCorrection("HIGHER");
rawMetricValue=correct.correction((int)rawMetricValue);
if (rawMetricValue > averageMetricValue && averageMetricValue > 18) {
float meanDeviation = ((rawMetricValue - averageMetricValue) / averageMetricValue) * 100;
return meanDeviation;
}
return 0;
}

}
public class UpstreamLowerMode extends DeviationMode{

public DeviationModeCorrectionFactory correctionFactory;

public UpstreamLowerMode(DeviationModeCorrectionFactory correctionFactory) {

this.correctionFactory = correctionFactory;
}

@Override
public float calculateMeanDeviation(float rawMetricValue,
float averageMetricValue) {
CorrectionStream correct=correctionFactory.getCorrection("LOWER");
rawMetricValue=correct.correction((int)rawMetricValue);
if ( averageMetricValue > rawMetricValue && averageMetricValue > 30) {
float meanDeviation = ((averageMetricValue - rawMetricValue) / averageMetricValue) * 100;
return meanDeviation;
}
return 0;
}

}

As we can see UpStreamBreachCalculator and the DownStreamBreachCalculator is getting the required object through abstraction DeviationModeCorrectionFactory and the DeviationMode. Lets code the other product which is CorrectionStream.

public interface CorrectionStream {

public float correction(int raw);
}
public class CorrectionDownStreamHigherMode implements CorrectionStream{

public float correction(int raw) {
// TODO Auto-generated method stub

return raw * 0.96f;
}

}
public class CorrectionDownStreamLowerMode implements CorrectionStream {

@Override
public float correction(int raw) {
// TODO Auto-generated method stub

return raw * 0.76f;
}

}
public class CorrectionUpperStreamHigherMode implements CorrectionStream {

@Override
public float correction(int raw) {
// TODO Auto-generated method stub

return raw * 0.90f;
}

}
public class CorrectionUpStreamLowerMode implements CorrectionStream {

@Override
public float correction(int raw) {
// TODO Auto-generated method stub

return raw * 0.86f;
}

}
import java.security.InvalidParameterException;

public class CorrectionDownStreamFactory implements DeviationModeCorrectionFactory {

@Override
public CorrectionStream getCorrection(String mode) {

CorrectionStream correction = null;
if (mode.equals("HIGHER")) {
correction = new CorrectionDownStreamHigherMode();
} else if (mode.equals("LOWER")) {
correction = new CorrectionDownStreamLowerMode();
} else {
throw new InvalidParameterException();
}

return correction;

}

}
import java.security.InvalidParameterException;

public class CorrectionUpstreamFactory implements DeviationModeCorrectionFactory{

@Override
public CorrectionStream getCorrection(String mode) {

CorrectionStream correction = null;
if (mode.equals("HIGHER")) {
correction = new CorrectionUpperStreamHigherMode();
} else if (mode.equals("LOWER")) {
correction = new CorrectionUpStreamLowerMode();
} else {
throw new InvalidParameterException();
}

return correction;

}

}

Lets code the client classes which will be getting the required object through the abstract factory


public abstract class BreachCalculator {

public abstract DeviationMode getDeviationMode(String mode);

public boolean compare(int rawdata, int aggregateData, int threshold,String mode) {

DeviationMode deviationMode=getDeviationMode(mode);

float meanDevaition = deviationMode.calculateMeanDeviation(rawdata,
aggregateData);

return deviationMode.compareMeanDeviation(meanDevaition, threshold);

}

}


import java.security.InvalidParameterException;

public class DownStreamBreachCalculator extends BreachCalculator {

DeviationModeCorrectionFactory deviationModeCorrectionFactory=new CorrectionDownStreamFactory();

@Override
public DeviationMode getDeviationMode(String mode) {

DeviationMode deviationMode = null;
if (mode.equals("HIGHER")) {
deviationMode = new DownStreamHigherMode(deviationModeCorrectionFactory);
} else if (mode.equals("LOWER")) {
deviationMode = new DownStreamLowerMode(deviationModeCorrectionFactory);
} else {
throw new InvalidParameterException();
}

return deviationMode;

}

}

import java.security.InvalidParameterException;

public class UpStreamBreachCalculator extends BreachCalculator {

DeviationModeCorrectionFactory deviationModeCorrectionFactory = new CorrectionUpstreamFactory();

@Override
public DeviationMode getDeviationMode(String mode) {

DeviationMode deviationMode = null;
if (mode.equals("HIGHER")) {
deviationMode = new UpstreamHigherMode(deviationModeCorrectionFactory);
} else if (mode.equals("LOWER")) {
deviationMode = new UpstreamLowerMode(deviationModeCorrectionFactory);
} else {
throw new InvalidParameterException();
}

return deviationMode;

}

}

finally lets write the test driver class


public class Driver {

public static void main(String[] args) {

String deviationMode = "LOWER";
BreachCalculator dsbc = new DownStreamBreachCalculator();
BreachCalculator usbc = new UpStreamBreachCalculator();

boolean breach = dsbc.compare(20, 50, 30, deviationMode);
boolean breach2 = usbc.compare(20, 50, 30, deviationMode);

if (breach) {
System.out.println("breach generated");
} else {
System.out.println("No breach");
}

}
}