I am trying to implement the chain of responsibility pattern, but it seems i am missing something because in the concrete classes the setnexthandler is not setting the next but is always the same. I guess my mistake is in the concrete classes in the processMalfunction() method in the else statems next.setNextHandler(next); i think it should be next.setNextHandler(Severity.Medium) for the first one. So here is the code if you could take a look. Here is the code.
public interface MalfunctionHandler
{
public void processMalfunction(Malfunction malfunciton);
public void setNextHandler(MalfunctionHandler handler);
}
public enum Severity
{
TRIVIAL, LOW, MEDIUM, HIGH
}
public class Malfunction
{
/**
* severity is a type of Severity
*/
Severity severity;
/**
* @param description describes the severity of the problem
*/
String description;
Malfunction(Severity severity, String description)
{
if(description == null)
{
description = "No description available. Probably serious.";
}
if(description.isEmpty())
{
description = "No description available. Probably serious.";
}
this.severity = severity;
this.description = description;
}
public Severity getSeverity()
{
return severity;
}
public String getDescription()
{
return description;
}
public void setSeverity(Severity severity)
{
this.severity = severity;
}
public void setDescription(String description)
{
this.description = description;
}
}
public class SpaceMonkey implements MalfunctionHandler
{
Severity severity;
MalfunctionHandler next;
File read = new File("expected-bronze.txt");
File f = new File("log-bronze.txt");
SpaceMonkey(Severity severity)
{
this.severity = severity;
System.out.println(FileUtility.readFile(read));
}
@Override
public void processMalfunction(Malfunction malfunction)
{
if (malfunction.getSeverity() == Severity.LOW)
{
final String[] splits = FileUtility.readFile(read).split("problem.");
for (String asset : splits)
{
if (asset.contains("Space monkey"))
{
FileUtility.writeFile(f, asset + "problem.");
System.out.println(asset + "problem.");
}
}
}
else
{
next.setNextHandler(next);
}
}
@Override
public void setNextHandler(MalfunctionHandler next)
{
this.next = next;
}
}
public class ServiceRobot implements MalfunctionHandler
{
Severity severity;
MalfunctionHandler next;
File read = new File("expected-bronze.txt");
File f = new File("log-bronze.txt");
ServiceRobot(Severity severity)
{
this.severity = severity;
}
@Override
public void processMalfunction(Malfunction malfuntion)
{
if (this.severity == severity)
{
String[] splits = FileUtility.readFile(read).split("problem.");
for(String asset : splits)
{
if(asset.contains("Service robot"))
{
FileUtility.writeFile(f, asset + "problem.");
System.out.println(asset + "problem.");
}
}
}
else
{
next.setNextHandler(next);
}
}
@Override
public void setNextHandler(MalfunctionHandler next)
{
this.next = next;
}
}
public class Engineer implements MalfunctionHandler
{
Severity severity;
MalfunctionHandler next;
File read = new File("expected-bronze.txt");
Engineer(Severity severity)
{
this.severity = severity;
}
@Override
public void processMalfunction(Malfunction malfuntion)
{
File f = new File("log-bronze.txt");
if (this.severity == severity)
{
String[] splits = FileUtility.readFile(read).split("problem.");
for(String asset : splits)
{
if(asset.contains("Engineer"))
{
FileUtility.writeFile(f, asset + "problem.");
System.out.println(asset + "problem.");
}
}
}
else
{
next.setNextHandler(next);
}
}
@Override
public void setNextHandler(MalfunctionHandler next)
{
this.next = next;
}
}
public class Captain implements MalfunctionHandler
{
Severity severity;
MalfunctionHandler next;
File read = new File("expected-bronze.txt");
Captain(Severity severity)
{
this.severity = severity;
}
@Override
public void processMalfunction(Malfunction malfuntion)
{
File f = new File("log-bronze.txt");
if (this.severity == severity)
{
String[] splits = FileUtility.readFile(read).split("problem.");
for(String asset : splits)
{
if(asset.contains("Captain"))
{
FileUtility.writeFile(f, asset + "problem.");
System.out.println(asset + "problem.");
}
}
}
else
{
next.setNextHandler(next);
}
}
@Override
public void setNextHandler(MalfunctionHandler next)
{
this.next = next;
}
}
public class FileUtility
{
/** This method appends a single string to a text file.
*
* @param f The file to write to
* @param entry The string to append
*/
public static void writeFile(File f, String entry)
{
try
{
final BufferedWriter out = new BufferedWriter(new FileWriter(f, true));
out.write(entry);
out.close();
} catch (IOException e)
{
System.err.println("Problem writing to the file");
}
}
/** This method resets the named text file.
*
* @param f The file to reset
*/
public static void resetFile(File f) {
try {
final BufferedWriter out = new BufferedWriter(new FileWriter(f, false));
out.write("");
out.close();
} catch (IOException e) {
System.err.println("Problem reset the file");
}
}
/** This method reads the contents of a text file.
*
* @param f The file to read from
* @return the contents of the text file as a single string
*/
public static String readFile(File f) {
final StringBuilder sb = new StringBuilder();
try {
final Scanner scanner = new Scanner(f);
while (scanner.hasNextLine()) {
sb.append(scanner.nextLine());
}
scanner.close();
} catch (FileNotFoundException e) {
System.err.println("Problem reading from file");
}
return sb.toString();
}
}
public class MalfunctionHandlerTest {
/**
* No-args constructor.
*/
public MalfunctionHandlerTest() {
}
/**
* Test of processMalfunction method.
*/
@Test
public void testProcessMalfunction() {
// Instanciate malfunction handlers
final SpaceMonkey sm = new SpaceMonkey(Severity.TRIVIAL);
final ServiceRobot sr = new ServiceRobot(Severity.LOW);
final Engineer e = new Engineer(Severity.MEDIUM);
final Captain c = new Captain(Severity.HIGH);
// Construct chain of responsbility
sm.setNextHandler(sr);
sr.setNextHandler(e);
e.setNextHandler(c);
// Create malfunctions
final Malfunction m1 = new Malfunction(Severity.HIGH, "Life support error. Oxygen "
+ "Recycling unit damaged, running at half efficiency");
final Malfunction m2 = new Malfunction(Severity.LOW, "Communications error. Cannot "
+ "find Jazz FM");
final Malfunction m3 = new Malfunction(Severity.MEDIUM, "Power supply error. Solar Panel "
+ "2 damaged, running at 31.3333% efficiency");
final Malfunction m4 = new Malfunction(Severity.MEDIUM, "Thermal regulation error. Sensor "
+ "damaged, manual temperature regulation needed");
final Malfunction m5 = new Malfunction(Severity.TRIVIAL, "Trash can full on C-Desk.");
final Malfunction m6 = new Malfunction(Severity.LOW, "Shower plug hole full of monkey hair");
final Malfunction m7 = new Malfunction(Severity.HIGH, "Proximity alert. Collision imminent");
// Clean log file
FileUtility.resetFile(new File("log-bronze.txt"));
// Process malfunctions
sm.processMalfunction(m1);
sm.processMalfunction(m2);
sm.processMalfunction(m3);
sm.processMalfunction(m4);
sm.processMalfunction(m5);
sm.processMalfunction(m6);
sm.processMalfunction(m7);
// Check log file
final String actualOutput = FileUtility.readFile(new File("log-bronze.txt"));
final String expectedOutput = FileUtility.readFile(new File("expected-bronze.txt"));
assertEquals(actualOutput, expectedOutput);
}
}
I don’t see any chain setup here. The principle of the pattern is to have each link of the chain do its part, and then call the next link somehow.
So a method should look like the following:
And of course, the chain should be setup before, using something like
Your current code consists in doing something if some condition is true, else assign the next handler of the next handler to itself: