首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这真的是松耦合的吗?

这真的是松耦合的吗?
EN

Software Engineering用户
提问于 2022-12-15 08:52:15
回答 3查看 241关注 0票数 1

我正在浏览一个现有项目的源代码,对一个实现完全搞不懂。该项目是在.Net 6中创建的,它是一个前端MVC项目。它是一个微服务项目的一部分,数据是通过一个API提供的。

现在问题是,有一个为API访问编写的泛型类,它有自己的接口。因此,无论哪个模块服务具有API调用,其相应的接口继承了处理API调用的通用接口。但是在服务调用的实现中,我们需要继承这个泛型API访问类的具体类,否则我们必须再次实现API访问逻辑。但是直接继承服务中的具体类,那么它不是松散耦合的,对吗?如果不是的话,我们真的需要一个通用API类的接口吗?我知道这是个愚蠢的问题,但不知怎么的,我的大脑没有朝着正确的方向工作。请帮帮我。

PFB代码示例

代码语言:javascript
复制
public interface IBaseService
{
    Task<T> SendAsync<T>(ApiRequest apiRequest);
}

public class BaseService : IBaseService
{
    API Access implementation
}

public interface IProductService : IBaseService
{
    Task<T> CreateProductAsync<T>(ProductDto productDto);
}

public class ProductService : BaseService, IProductService
{
    private readonly IHttpClientFactory _clientFactory;

    public ProductService(IHttpClientFactory clientFactory) : base(clientFactory)
    {
        _clientFactory = clientFactory;
    }

    public Task<T> CreateProductAsync<T>(ProductDto productDto)
    {
        throw new NotImplementedException();
    }
}
EN

回答 3

Software Engineering用户

发布于 2022-12-15 18:39:21

我的猜测是,这里的想法是客户端代码使用特定于服务的接口(如您的IProductService),将它们与服务实现解耦。

如果是这样的话,预期的依赖结构如下所示:一些客户端代码将多形性地使用IProductService-typed参数,并将向其提供具体的产品服务。

例如,客户端代码可能使用依赖项注入来获得IProductService依赖项。在这个场景中,客户端代码不了解ProductService,也不依赖于它。

但是,由于假定实现的一部分(以及接口的一部分)是在所有这些服务之间共享的,所以将其提取到IBaseService中,然后由具体的BaseService类实现。

可能是IBaseService本身作为对其他上下文中客户端代码的依赖而有用,或者它只是作为定义其他(特定于服务的)接口的一种重用形式。

现在,你问:

但是直接继承服务中的具体类,那么它不是松散耦合的,对吗?

不,继承一个具体的类也是一种有效的去耦方法,实际上它对于某些设计模式是必要的。一般来说,它提供的解耦程度比继承接口或抽象类要小--假设客户端代码直接使用基类。子类获得正确实现的难度也可能更大(根据Liskov替换原则)。

但在您的情况下,据我所知,BaseService类并不意味着客户端直接使用;它只是实现共享成员,并执行

代码语言:javascript
复制
ProductService : BaseService, IProductService
{
   // ...
}

您不必一次又一次地为每个具体类键入所有共享成员(这是IProductService继承IBaseService所需要的)--也就是说,它有助于保持代码干的

因此,这不是一个问题,只要客户端代码不了解BaseService类(它不是直接使用/引用)。

在详细的视图中,您有:

但是在更“放大”的粗粒度视图中,您可以看到以下内容:

基本上和最上面的图片是一样的。

现在,是否有一个比这更好的设计是另一回事,并取决于您的领域的具体情况和您的需求。也许这个设计有一个很好的理由,也许没有-你必须和你的团队成员讨论这个问题。

正如其他人提到的那样,如果可能的话,可以将BaseService中包含的功能单独作为一个单独的东西。一个职责更窄的类,它不在服务层次结构中,然后将其作为对具体服务(如ProductService )的依赖注入。这都取决于您想要的是什么解耦,以及您希望如何在类之间分配各种责任。

票数 2
EN

Software Engineering用户

发布于 2022-12-15 13:04:40

你必须问,什么是与什么相结合的。

在这里,您的BaseService与所有东西耦合在一起,坦率地说,它看起来是一个糟糕的设计,为什么不注入呢?

但是,您的应用程序是松散地耦合到ProductService的。这可能是最重要的一点。

票数 1
EN

Software Engineering用户

发布于 2022-12-15 16:23:05

我认为这与BaseService类的上下文有关,如果它只是实现了Task<T> SendAsync<T>(ApiRequest apiRequest);,您可以简单地删除它,然后在ProductService类中实现该方法,因此代码如下:

代码语言:javascript
复制
public interface IBaseService
{
    Task<T> SendAsync<T>(ApiRequest apiRequest);
}

public interface IProductService : IBaseService
{
    Task<T> CreateProductAsync<T>(ProductDto productDto);
}

public class ProductService : IProductService
{
    private readonly IHttpClientFactory _clientFactory;

    public ProductService(IHttpClientFactory clientFactory) : base(clientFactory)
    {
        _clientFactory = clientFactory;
    }

    Task<T> SendAsync<T>(ApiRequest apiRequest) {
        //API Access implementation
    }

    public Task<T> CreateProductAsync<T>(ProductDto productDto)
    {
        throw new NotImplementedException();
    }
}

如果没有,即BaseService包含许多方法,将继承替换为组合,并使用多态将其作为参数传递给ProductService (参数应该是IBaseService类型,而不是BaseService类型,因此代码如下:

代码语言:javascript
复制
public interface IBaseService
{
    Task<T> SendAsync<T>(ApiRequest apiRequest);
}

public class BaseService : IBaseService
{
    API Access implementation
}

public interface IProductService : IBaseService
{
    Task<T> CreateProductAsync<T>(ProductDto productDto);
}

public class ProductService : IProductService
{
    private readonly IHttpClientFactory _clientFactory;
    private IBaseService baseService;

    public ProductService(IBaseService baseService, IHttpClientFactory clientFactory) : base(clientFactory)
    {
        _clientFactory = clientFactory;
        this.baseService = baseService;
    }

    public Task<T> CreateProductAsync<T>(ProductDto productDto)
    {
        throw new NotImplementedException();
    }
}

这样,您就可以访问所有BaseService方法,而无需与其高度耦合。

票数 1
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/442845

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档