We are the Dev Teams of
  • brands
  • ebay_main
  • ebay
  • mobile
<
>
BLOG

A Conversation Around Decorators

by Oleg Majewski
in Tutorials

Camels Dialog

What's this?

interface Validator {
	public Boolean validate(String value);
}

An interface.

Then what is this?

public class SimpleValidator implements Validator {
    public Boolean validate(String value) {
	return value != null && !value.isEmpty();
    }
}

A simple empty string validator.

If I have to log validation I do:

public class SimpleValidator implements Validator {

	private static final Logger log = 
            LoggerFactory.getLogger(SimpleValidator.class);

	public Boolean validate(String value) {
            log.info("validate {}", value);
	    return value != null && !value.isEmpty();
        }
}

You can, but you'd violate the single responsibility principle. You could try it this way:

public class LoggedValidator implements Validator {

	private final Validator origin;

	public LoggedValidator(Validator validator) {
	    this.origin = validator;
        }

	public Boolean validate(String value) {
            log.info("validate {}", value);
	    return origin.validate(value);
        }
}

Looks like boilerplate, how is it useful?

You compose the additional behavior instead of changing the origin implementation:

Validator validator = new SimpleValidator();
validator = new LoggedValidator(validator);

I see, then additionally adding monitoring is as simple as:

Validator validator = new SimpleValidator();
validator = new LoggedValidator(validator);
validator = new MonitoredValidator(validator);

Right.

Where the implementation is:

public class MonitoredValidator implements Validator {

	private final Validator origin;
	private final Timer timer;

	public MonitoredValidator(Validator validator) {
	    this.origin = validator;
	    this.timer = TimerFactory.getTimer("validator timer");
        }

	public Boolean validate(String value) {
	    Timer.Context ctx = timer.time();
	    try {
	        return origin.validate(value);
             } finally {
	         ctx.stop();
             }
    	}
}

Looks good to me.

Then if I later have to change the logging, all I have to do is to change the LoggedValidator?

Yes.

And If I don’t want to do monitoring any more, then I remove the MonitoredValidator and that was it?

Validator validator = new SimpleValidator();
validator = new LoggedValidator(validator);
// validator = new MonitoredValidator(validator);

Yes.

One last thing,  is this in any way useful for unit testing?

You can create tests for validation logic, without caring about logging and monitoring. If you want to test the last two, you can do this as well without caring about the validation itself.

Alright, thank you for the conversation.

You are welcome.

Camel photograph: ©Peter Nijenhuis, licensed under CC BY-NC-ND 2.0

Java, programming

?>