C#中的SOLID原则——如何实现更具体的接口

dns*_*_nx 5 c# solid-principles

我目前是清洁代码和 SOLID 原则主题的新手。

我们已经UseCase为特定任务编写了一个。

using BusinessLogic.Classes.BusinessLogic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLogic.UseCases
{
    public class DoASpecificTask<T> : Interfaces.IUseCase
        where T : Interfaces.Connections.IQuery
    {
        T _Query;
        Interfaces.Connections.IConnection<T> _Connection;
        object _Parameters;
        string _ServiceName;
        Interfaces.ISendMessage _MessageSender;

        public DoASpecificTask(T query, Interfaces.Connections.IConnection<T> connection, object parameters, string serviceName, Interfaces.ISendMessage messageSender)
        {
            _Query = query;
            _Connection = connection;
            _Parameters = parameters;
            _ServiceName = serviceName;
            _MessageSender = messageSender;
        }

        public void Execute()
        {
            Interfaces.Connections.IQueryResultList resultList = ExecuteReadDataOnConnection<T>.GetList(_Query, _Connection, _Parameters);
            if (!ValidateQueryResultListItems.Validate(resultList))
            {
                EndImp3Service.EndService(_ServiceName);
                _MessageSender.SendMessage('Message','for@bar.com');
            }
            
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

据我了解 SOLID,解决方案/类/方法应该对扩展开放,对更改关闭(开放/封闭原则)。我们现在的问题是,我们已经创建了一个非特定的通用interface消息来发送消息

Interfaces.ISendMessage

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLogic.Interfaces
{
    public interface ISendMessage
    {
        void SendMessage(string message, string recipient);
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上,我们想通过电子邮件发送消息,因此我们创建了另一个接口ISendEmail,它实现了ISendMessage. 一封电子邮件也有一个参数subject,它在通用接口ISendMessage(方法SendMessage())中没有实现。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLogic.Interfaces
{
    public interface ISendEmail : ISendMessage
    {
        void SendMessage(string message, string recipient, string subject);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我的问题是,我们怎么能不具体UseCase地保持开放以进行扩张?可能在某个时候我们想要发送 WhatsApp 或 Telegram 消息而不是电子邮件。如果我执行的财产ISendMessageUseCase,我没有参数subject

我的意思是UseCase

_MessageSender.SendMessage('Message','for@bar.com');
Run Code Online (Sandbox Code Playgroud)

因为我们指定了通用接口ISendMessage,所以不能subject在方法中提供a 。如果我们更改ISendMessageISendEmail,我们就不再开放了,不是吗?

如何做到这一点,或者我们是否误解了完全错误的事情?


更新

首先,感谢您的意见和解决方案。我认为,这正是我们作为 SOLID 初学者需要了解的问题,什么时候要具体,而不是试图制作一个在任何情况下都可以做任何事情的程序。当然,SOLID并不是说完全不改代码,问题是代码需要改到哪里

我认为,在所有提供的解决方案中,问题只是转移了。无论如何,我需要指定我在UseCase. 如果我要使用@Martin Verjans 的解决方案,我可以使用 type IMessage,但是我必须在参数中具体说明。通过使用generics,我有同样的问题。@SomeBody 的解决方案,不符合开闭原则。

我们的目标是实现是在非特异性的UseCase,所以我们并不需要改变UseCase自己,如果我们决定发送WhatsApp的消息,而不是电子邮件。实际上我没有看到这个选项。

Som*_*ody 0

您可以修改您的界面ISendMessage,让它知道它是否支持某个主题:

public interface ISendMessage
    {
        bool SupportsSubject { get; }
        void SendMessage(string message, string recipient);
        void SendMessage(string message, string recipient, string subject);
    }
Run Code Online (Sandbox Code Playgroud)

你会这样称呼它:

if(_MessageSender.SupportsSubject)
 {
 _MessageSender.SendMessage("Message","for@bar.com", "the subject"); 
 }
else
 {
 _MessageSender.SendMessage("Message","for@bar.com");
 }
Run Code Online (Sandbox Code Playgroud)

这种方式也用在基类库中。例如,该类Stream有一个名为 的属性CanSeek。当然,如果您在接口的实现中有多个这样的可选参数,那么这将变得不切实际,因为这将导致大量的 if 检查。