Standardization with interface in .Net

I have a strange question about OOP and interfaces that messed up my mind trying to find a better design.

There are two different classes that do the same job (for example, sending a message) in different environments. These two environments use different parameters to determine the recipient; one uses a mailing address and the other uses a username. Thus, both classes have the same, but slightly different ways of sending a message.

MessageSenderViaMailManager.cs

public bool SendMessage(string recipientMailAddress, string message) { .. } 

MessageSenderViaUsernameManager.cs

 public bool SendMessage(string recipientUserName, string message) { .. } 

In both classes, there are other similar methods that are responsible for the same work, but may require different parameters. To use these managers with an interface, I created a name that is IMessageSenderManager and contains a definition similar to this.

 public bool SendMessage(string recipientUserName, string recipientMailAddress, string message); 

So, both SendMessage methods in my classes have been changed to:

 public bool SendMessage(string recipientUserName,string recipientMailAddress, string message) { .. } 

With this new SendMessage method, I can use the appropriate parameter to use as the recipient (email address or username). This seems to be fine, but the implementation looks weird. Because I have to send all the parameters, not knowing what will be used at runtime during encoding. For instance:

 // 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 the code above, sending a message to a mailing address looks similar.

In my opinion, this is not a very good design, so I started thinking about the best solution. Bacause, if I want to implement another MessageSender provider that uses a different descriptor for the receiver, I need to add another parameter to my interface, so for all classes. I thought I could change two recipient parameters with one common recipient parameter and send the appropriate value for the context. But I'm trying to use this in a dynamic environment, and the way (via username or mail) will be determined at runtime, so I could not use this.

I plan to do this, a flexible library that can be used untied or unit test friendly for other developers, and I do not want to confuse them with meaningless parameters or poor design.

Is there a better design for this situation?

EDIT:

Actually, by my mistake, I forgot a very large and important part of my question, I regret it. As you can see from the answers, there are several alternatives to solve my first problem described above. But after? I mentioned in the code, the interface is returned from the MessageSenderFactory () method, but I do not know which message sender manager has returned. Therefore, I have two options:

  • Write a condition to check which manager returns from the method, and send the required parameters for this manager with the correct values ​​and send to others empty.
  • Send all parameters with the corresponding values ​​regardless of the manager, so both of them can work without problems. But in the future, if another manager is added, than I will need to send additional parameters for this manager, every time.
  • Is there any other way that I could not think of yet?

Also, methods other than SendMessage may require different parameters according to the manager, which is unknown at runtime. For instance:

MessageSenderViaMailManager The AddContact method may require the following parameters:

  • Contact name
  • Contact mail
  • contact number
  • Contact MailType (rich, plain)

or MessageSenderViaUserNameManager AddContact may need to complete the following parameters:

  • Contact name
  • Contact mail
  • Username contact
  • Contact Message Platform (Twitter, facebook, vs)
  • Contact sender name

Thus, this makes everything very complex. How should my IMessageSenderManger AddMethod be? Should they contain all parameters? Should I overload it? Or should I put the general parameters in the method and make other parameters that are changed by the anonymous manager (for example, HtmlHelper in MVC)

I know this question is not very strong, and I am not good at English.

GitHub EDIT:

I created a small example and uploaded to github, hope this helps me better explain my question https://github.com/bahadirarslan/InterfaceDesign

+6
source share
4 answers

Update: Quickly change the answer for clarity.

I changed the code to use 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; } } 

Thus, if you have a user ID, you use one of the following lines depending on the type of recipient (as is the case with the switch in the git example):

 var manager = MessageSenderManagerFactory.Create(new MailRecipient(userId)); var manager = MessageSenderManagerFactory.Create(new UserNameRecipient(userId)); 

The logic of which type of Recipient use should not be based on a user ID. There must be a flag or parameter in the database or a User object that indicates this.

Then send a message:

 manager.SendMessage(message); 

Disclaimer: Not verified code.

+1
source

Why don't you configure the interface as follows:

 public bool SendMessage(string recipient, string message) { .. } 

Then, within the logic of each class, you add some code to verify recipient information, so for example, your implementation, which expects an email address, adds verification to verify that you passed, is a valid email address. Then in your implementation, which expects a username, confirm, you can find the user.

You can always implement this check in your factory so that it knows which class to create.

+1
source

I would create a class MailMessage that has a recipients property. Then in this MailMessage class MailMessage are 2 overloads of the AddRecipient method. One for each of the ways to add recipients.

+1
source

Design is always the result of a specific set of requirements. No different from OO: there are almost endless ways to implement a library that can send emails in various circumstances. Which design / implementation is good depends entirely on your situation. Therefore, asking “which design is better” is pointless if you have not provided more detailed information about your requirements:

Why do you / need to reverse engineer what you have already implemented?

Nevertheless, I agree that the abstraction you choose (one method with several parameters that are optional or mutually exclusive, depending on what information the client had) looks bad. As a rule, methods and classes are best simple and simple, so each parameter makes sense. In other words: your first design with two different classes - IMHO, is better than your second, because it is more consistent with the principle of shared responsibility .

+1
source

Source: https://habr.com/ru/post/976006/


All Articles