Reputation: 2801
I want to build a Register class for a website. Here are my use cases --
Here is the design that I thought about
Interface IRegister
{
string RegisterUser(string email, string password);
}
public class Register:IRegister
{
public string RegisterUser(string email, string password)
{
//Call IsUserExist and SentActivationEmail method internally
}
private bool IsUserExist()
{
}
private void SendActivationEmail()
{
}
}
I don't want to mention IsUserExist and SendActivationEmail method in IRegister so that it remains simple. Now how I can enforce a developer who will implement the Register class that he/she should use IsUserExist and SendActivationEmail method and do all operations as mentioned in use case. And does this design violate SRP principle?
Upvotes: 1
Views: 278
Reputation: 5551
If you want to enforce that developers use those methods then you should be declaring an abstract class with protected abstract methods rather than an interface. Then the definition enforces the methods, but the developer is free to implement them however they need.
public abstract class Register:IRegister
{
public string RegisterUser(string email, string password)
{
//Call IsUserExist and SentActivationEmail method internally
}
protected abstract bool IsUserExist();
protected abstract void SendActivationEmail();
}
That being said, to keep with the SRP principle I would pull the email part of it out into a dependent IActivationEmailer interface. Emailing and registering are really two different actions and should be kept separate.
public interface IActivationEmailer {
void SendActivationEmail();
}
public abstract class Register:IRegister
{
private IActivationEmailer m_emailer;
protected Register(IActivationEmailer emailer){
// store emailer to field
m_emailer = emailer;
}
public string RegisterUser(string email, string password)
{
//Call IsUserExist and m_emailer.SentActivationEmail method internally
}
protected abstract bool IsUserExist();
}
Upvotes: 2
Reputation: 1693
I agree with Mikes answer. A slightly different approach would be to apply a template method and let subclasses define what they want to do on the registration (I'm not familiar with C# so please bear with me):
public abstract class Register:IRegister
{
public string RegisterUser(string email, string password)
{
if (this.IsUserExist())
{
//throw the error
}
else
{
this.performRegistration();
this.notifyUSer();
}
}
protected abstract bool IsUserExist();
protected abstract notifyUSer();
protected abstract performRegistration(){}
}
and then, as Mike pointed, you could define:
public interface IActivationEmailer {
void SendActivationEmail();
}
public class CustomRegister
{
private IActivationEmailer m_emailer;
public CustomRegister(IActivationEmailer emailer){
// store emailer to field
m_emailer = emailer;
}
protected abstract bool IsUserExist(){...}
protected abstract notifyUSer() {this.m_emailer.SendActivationEmail();}
protected abstract performRegistration(){...}
}
So basically the Register class is defining the steps to follow during a registration but it is leaving the subclasses to state how to implement those steps.
HTH
Upvotes: 0