0

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:

uml diagram

  • 1
    Will the MailerServiceDelegate be changed some when during the lifetime of a MailerService instance? – Bernhard Hiller Oct 5 '18 at 8:02
  • @BernhardHiller That's a good point. I had not taken into account this issue. Yes the delegate might be changed... That's therefore another issue. – balteo Oct 5 '18 at 8:25
  • I meant that's therefore an additional issue with the current design. :-) – balteo Oct 5 '18 at 8:37
1

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);
    }
}
0

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.

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.