Java – Strategy Pattern Implementation

design-patternsjavaooad

I have to generate a code that will send through SMS or Email to implement the One Time Password (OTP) requirement of our client.

I just finished creating the design using strategy pattern, .
Please see screenshot for the UML design.

This it the first time I've used strategy pattern in real life projects so I would like to ask if I'm doing it right.

Below is just a sample code that will be used by client.

 //OTPGeneratorStrategy generatorStrategy = new EmailGeneratorStrategy("test@gmail.com"); for sending to Email for example
OTPGeneratorStrategy generatorStrategy = new SmsGeneratorStrategy(993454454545);
OTPGeneratorContextgeneratorContext = new OTPGeneratorContext(generatorStrategy);
context.generate("1-12345-0");

OTPValidatorStrategy validatorStrategy = new SmsValidatorStrategy();
OTPValidatorContext validatorContext = new OTPValidatorContext (validatorStrategy );
try {
validatorContext.validate("1-12345-0","e7241f");
} catch (InvalidVerificationKeyException ivk) {
System.out.println("Verification key is invalid!");
} catch(VerificationKeyExpiredException vke) {
System.out.println("Verification key is already expired, Please regenerate");
}

Updated:

Thank you for the feedback, actually I was not able to update my latest UML design and already separated the generation and validation. See this

And the reason why I've used Exception rather than enums because the project was built in java 1.4.

Best Answer

First thing that strikes me as a problem is using exceptions for validation result. Don't use exceptions for application logic. Just return an enum value. I would assume there are not many ways validation can end up.

Next thing I would question is using of two strategies. What would happen if you used SMS generator with Email validator? To me, it seems there should be just one strategy with both generate and validate methods. As for "merging the two violates SRP", I would actually say having them separate violates SRP. SRP is about cohesion. And cohesion works both ways. It separates non-cohesive code and joins cohesive code that was split. Ask yourself "If I changed how Email one-time-password policy worked, would I change only generator or validator or would I have to change both?". I'm quite sure you would need to change both, meaning generation and validation are cohesive parts. If you are worried about putting email sending into the strategy implementation, then that should be strategy's concern. OTPContext doesn't need to be bothered by that. It doesn't need to know generation uses some special logic, that is not relevant to validation.

Last nitpick is that I would prefer if strategy was set to OTPContext in a constructor instead of getters/setters. What would happen if you changed the validator strategy after code was generated? You should keep things read-only unless there is explicit requirement for things to change.