Should multiple service level objects share a DAO?
I have a Contact class that contains a PortalAccount object. When I want to create a "portal account" for a contact, the account is created remotely in the portal app using soap / axis, and then the contact portal "Account" is populated and the contact is saved (the local database stores the remote account information like id username and username, etc.).
So, I have a PortalServiceImpl service class that has methods for actually creating a user on the remote portal given a Contact instance.
With all this information in mind, my question is this: should PortalServiceImpl get an instance of the ContactDAO object and actually do the save, or should the PortalServiceImpl class just create the remote user, change the one passed in the Contact object, and let the client be responsible for saving?
Method 1:
class ServiceFacadeImpl {
public void createPortalAccount(Contact contact) {
// here the contact is implicitly saved
this.portalService.createPortalAccount(contact);
}
}
Method 2:
class ServiceFacadeImpl {
public void createPortalAccount(Contact contact) {
// here contact is implicitly modified
this.portalService.createPortalAccount(contact);
this.contactDAO.save(contact);
}
}
Both methods consider me wrong. Method 1 doesn't feel right because the PortalService creates a remote user and maintains contact with the database (albeit through a DAO interface). Method 2 does not feel like this because I have to assume that the PortalService is modifying the contact that I am passing it to.
I also have a feeling that I am not seeing any other errors, such as potentially not processing transactions sequentially.
(BTW, I've already used both methods and don't want to continue refactoring in an endless circle. Something seems to be wrong here.)
a source to share
Are you sure it's nice that you have different contact IDs locally and remotely? It seems to me that this is wrong, but maybe I just don't know your domain.
In my application, all new contacts are sent via a web service to the remote portal and saved there. So when I save a new contact locally, it is sent to the remote portal and saved there. Maybe you need the same?
If the above thoughts are not acceptable to you, I would do it this way:
class ServiceFacadeImpl {
public void CreatePortalAccountAndSaveContact(Contact contact) {
try
{
contact.portalAccount = this.portalService.createPortalAccount(contact);
this.contactDAO.save(contact);
}
catch(...)
{
// do cleanup, for example do you need to delete account from remote
// portal if it couldn't be saved locally?
// If yes, delete it from portal and set contact.portalAccount = null;
}
}
}
Some might say that CreatePortalAccountAndSaveContact violates the Single Responsibility principle, but in this situation it is absolutely normal, because as I understand it, you need this operation for atomic. Right?
Or you can add a boolean flag to the method to indicate if you want to save the contact. But if you always need to keep in touch with the PortalAccount right after receiving it from the remote portal, then you don't need a boolean flag.
PS. Why are you using the "this" keyword? Are you a private user of the PortalService? If so, then perhaps you need to revise your naming convention and name the private members with a "_" prefix, for example (I think this is the most popular) like _portalService - then it should be easy to understand that _portalService is a private user. Sorry for the offtopic.
Good luck.
a source to share