My question relates to usage of delegation together with inheritance and dependency injection.
I have a MailerService
class that requires a delegate in order to do its job.
Furthermore, I have a hierarchy of delegates with an abstraction: MailerServiceDelegate
together with a number of implementations amongst others an EmailResetDelegate
.
Here is the Spring class using the delegate:
@Service
public class MailerService {
private static final boolean IS_HTML = true;
private static final boolean MULTIPART = true;
private static final String ENCODING = "UTF-8";
...
private final JavaMailSender mailSender;
private MailerServiceDelegate mailerServiceDelegate;
public MailerService(...
JavaMailSender mailSender,
...) {
this.mailSender = mailSender;
}
public void setMailerServiceDelegate(MailerServiceDelegate mailerServiceDelegate) {
this.mailerServiceDelegate = mailerServiceDelegate;
}
public void sendMail(Object ...objects) {
try {
final Context ctx = new Context();
...
mailerServiceDelegate.setContext(ctx, objects);
final MimeMessage mimeMessage = mailSender.createMimeMessage();
...
mailSender.send(mimeMessage);
} catch (MessagingException | UnsupportedEncodingException e) {
throw new MailerException(e);
}
}
}
Here is the implementation for the delegate:
//As of now this is a plain class and not a spring dependency
public class EmailResetDelegate implements MailerServiceDelegate {
And the client:
@Service
public class Client {
private MailerService mailerService;
public Client(MailerService mailerService) {
this.mailerService = mailerService;
}
public void sendEmailAddressResetRequest(UserAccount userAccount, EmailReset emailReset) {
mailerService.setMailerServiceDelegate(new EmailResetDelegate());
mailerService.sendMail(userAccount, emailReset);
}
}
The trouble with the current design is that I have to set the delegate manually using the setMailerServiceDelegate
method from the client. Also I am mixing dependency injection with manual instantiation. Can someone suggest a better design ?
Edit: Here is the diagram for the current design:
2 Answers 2
It seems that MailService should only have one MailerServiceDelegate during it's lifetime. I am not sure if you can change MailService, but I think that it's current implementation have some flaws.
If you can not change MailService, then the best option is to use your own adapter on MailService which will contain multiple MailServices instances, for each MailServiceDelegate:
public class MailServiceAdapter {
MailService _emailResetService;
MailService _otherMailService;
public MailServiceAdapter(MailServiceFactory mailServiceFactory){
_emailResetService = mailServiceFactory.CreateMailResetService();
_otherMailService = mailServiceFactory.CreateOtherMailService();
}
public void sendEmailAddressResetRequest(UserAccount userAccount, EmailReset emailReset)
{
_emailResetService.sendEmail(userAccount, emailReset);
}
public void sendOtherStuff(UserAccount userAccount, OtherEmail otherEMail)
{
_otherMailService.sendEmail(userAccount, otherEMail);
}
}
Since it's a Spring's Service, I'll assume your MailerService instance is a singleton.
Doing this mailerService.setMailerServiceDelegate(new EmailResetDelegate());
in a real application means that sooner or later you will enter in a race condition where two differents thread won't want to use the same delegate.
So since your class is singleton, its attribute must be final and not mutable, at least once you passed an additional post-init method of Spring.
If you really want to keep your logic of delegate, use a factory as an intermediary between your service and your delegates.
That factory will return the correct delegate instance depending of a parameter you pass to it.
Note that since you have a method setContext
in your mail, that means the factory will have to return a new instance everytime it's called. If you want to use a singleton, change your design so that your delegate won't change once properly initialized.
Explore related questions
See similar questions with these tags.
MailerServiceDelegate
be changed some when during the lifetime of aMailerService
instance?