Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Standardization with Interface in .Net

Tags:

c#

oop

interface

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,

  1. Write if condition to check which manager is returned from method and send mandatory parameters for that manager with proper values and send others empty.
  2. Send all parameters with proper values regardless of manager, so both of them can work without problem. But in future, if another manager is added than i will need to send extra parameters for that manager, everytime.
  3. Is there another way which i couldn't think yet?

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:

  • Contact Name
  • Contact Mail
  • Contact Phone Number
  • Contact MailType (rich, plain)

or MessageSenderViaUserNameManager's AddContact method may require parameters below:

  • Contact Name
  • Contact Mail
  • Contact User Name
  • Contact Message Platform (Twitter, facebook, vs)
  • Contact Sender Name

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

like image 487
bahadir arslan Avatar asked Sep 29 '14 13:09

bahadir arslan


People also ask

Why interface is used in C#?

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 need to use interface?

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.

Why do we use interface in OOP?

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".

What is interface class in C# with example?

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.


2 Answers

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.

like image 95
Sani Singh Huttunen Avatar answered Oct 25 '22 09:10

Sani Singh Huttunen


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.

like image 41
Pheonyx Avatar answered Oct 25 '22 09:10

Pheonyx