I have a weird question about OOP and interfaces which messed up my mind while trying to find best design.
There are two different classes which make same work (for example sending message) at different environments. These two environments use different parameters to define recipient; one is using mail address and the other one is using user name. So both the classes have same but slightly different methods for sending message.
MessageSenderViaMailManager.cs
public bool SendMessage(string recipientMailAddress, string message) {
..
}
MessageSenderViaUsernameManager.cs
public bool SendMessage(string recipientUserName, string message) {
..
}
There are other similar methods in both classes, responsible for same work but may require different parameters. To make usable these managers with an interface, i created one which name is IMessageSenderManager and contains a definition like this.
public bool SendMessage(string recipientUserName, string recipientMailAddress, string message);
So both SendMessage methods in my classes were changed to this:
public bool SendMessage(string recipientUserName,string recipientMailAddress, string message) {
..
}
With this new SendMessage method, i can use appropriate parameter to use as recipient (mail address or username). This seems ok, but implemantation looks like weird. Because i have to send all parameters, without knowing which will be used at runtime while coding. For example:
// Sending message via username implementation
string userName = GetUserNameFromSomeWhere();
string mailAddress = GetUserMailFromSomeWhere();
IMessageSenderManager manager = MessageSenderFactory();
manager.SendManager(userName, mailAddress, "This messaged sent by your user name");
Like code above, sending message by mail address looks similar.
In my opinion this is not a good design so i started to think for a better solution. Bacause if i want to implement another MessageSender provider which uses different descriptor for recipient, i have to add another parameter to my interface, so to all classes. I thought, i could change two recipient parameters with one general recipient parameter and send appropriate value for context. But i am trying to use this in dynamic enviroment and the way (via user name or mail) will be determined in runtime, so i couldn't use this.
I am planing to make this, a flexible library which can be used decoupled or unit test friendly for other developers and i don't want to confuse them with meaningless parameters or with bad design.
Is there any better design for a situation like this?
EDIT:
Actually by my mistake, i forgot very big and important part of my question, i am sorry for this. As you can see from answers there are some alternatives to solve my first problem which described above. But then? I mentioned in code, interface is returned from MessageSenderFactory() method but i don't know which message sender manager returned. So i have two options,
Also other methods than SendMessage may require different parameters according to manager which is unknown at runtime. For example:
MessageSenderViaMailManager's AddContact method may require parameters below:
or MessageSenderViaUserNameManager's AddContact method may require parameters below:
So this makes everything very complicated. How my IMessageSenderManger's AddMethod should be? Should it contain all parameters? Should i overload it? Or should i put common parameters in method and make other parameters which vary by manager anonymous (like HtmlHelper in MVC)
I know this is question isn't very solid and i am not good at describing in English.
GitHub EDIT:
I created a small example and uploaded to github, i hope this can help me to explain my question better https://github.com/bahadirarslan/InterfaceDesign
By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is important in C# because the language doesn't support multiple inheritance of classes.
Why do we use an Interface? It is used to achieve total abstraction. Since java does not support multiple inheritances in the case of class, by using an interface it can achieve multiple inheritances. It is also used to achieve loose coupling.
Interfaces allow you to specify what methods a class should implement. Interfaces make it easy to use a variety of different classes in the same way. When one or more classes use the same interface, it is referred to as "polymorphism".
Interface in C# is a blueprint of a class. It is like abstract class because all the methods which are declared inside the interface are abstract methods. It cannot have method body and cannot be instantiated. It is used to achieve multiple inheritance which can't be achieved by class.
Update: Former answer redacted for clarity.
I've changed the code to utilize your structure.
public static class MessageSenderManagerFactory
{
public static IMessageSenderManager Create(IRecipient recipient)
{
return new MessageSenderManager { Recipient = recipient };
}
}
public interface IMessageSenderManager
{
public IRecipient Recipient { get; set; }
bool SendMessage(string message);
}
public class MessageSenderManager : IMessageSenderManager
{
public IRecipient Recipient { get; set; }
public bool SendMessage(string message)
{
// At this point you construct the actual message and sending mechanism.
// You'll have all the information you need in the TheUser property of Recipient.
// The following is an example how this can be implemented but since you have not
// provided what information you need to send or HOW you send the message I can't
// be more specific.
var messageToSend = new Message(message);
messageToSend.Address = Recipient.GetRecipientAddress();
messageToSend.Send();
}
}
public interface IRecipient
{
public string GetRecipientAddress();
}
public abstract class RecipientBase
{
public User TheUser { get; set; }
private RecipientBase() { }
protected RecipientBase(string userId) { TheUser = FindUserById(userId); }
}
public class MailRecipient : RecipientBase, IRecipient
{
public MailRecipient(string userId) : base(userId) { }
public string GetRecipientAddress() { return TheUser.Mail; }
}
public class UserNameRecipient : RecipientBase, IRecipient
{
public UserNameRecipient(string userId) : base(userId) { }
public string GetRecipientAddress() { return TheUser.UserName; }
}
So when you have the user id you use one of the following lines depending the type of recipient (as you do with switch-case in your git example):
var manager = MessageSenderManagerFactory.Create(new MailRecipient(userId));
var manager = MessageSenderManagerFactory.Create(new UserNameRecipient(userId));
The logic of which type of Recipient
to use should not be based on the users id. There should be a flag or setting in the database or User
object that specifies this.
Then to send the message:
manager.SendMessage(message);
Disclaimer: Code not tested.
Why not have you interface as follows:
public bool SendMessage(string recipient, string message) {
..
}
Then within the logic of each class you add some code to validate the recipient information, so for example you implementation that expects an e-mail address, add validation to check what you are passed is a valid e-mail address. Then in your implementation that expects a username, validate you can find the user.
You could always implement that checking in your factory so it knows which class to create.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With