c# - C#中的重用抽象原则

标签 c# oop abstraction solid-principles

在我们的 C# MVC 应用程序中,我们有很多接口(interface)与实现它们的对象一对一映射。即:基本上,对于创建的每个对象,都执行了“提取接口(interface)”操作。

Moq 使用这些接口(interface)为我们的单元测试生成模拟对象。但那是唯一一次重新使用接口(interface)。

我们系统中没有具体对象实现多个接口(interface)。

谁能告诉我这是否会在以后造成问题?如果是这样,它们会是什么?

我在想,我们的应用程序有很多重复,例如在这两个接口(interface)中(编辑:在我们的服务层中)唯一不同的是方法名称和它们采用的参数类型,但是从语义上讲,他们对发送消息的存储库做同样的事情:

interface ICustomer
{
    void AddCustomer(Customer toAdd);
    void UpdateCustomer(Customer toUpdate);
    Customer GetById(int customerId);
}

interface IEmployee
{
    void AddEmployee(Employee toBeAdded);
    void UpdateEmployee(Employee toUpdate);
    Employee GetById(int employeeId);       
}

这就是我认为重用抽象原则应该发挥作用的地方,即将代码转换成如下形式:

public interface IEmployee: IAdd<Employee>, IUpdate<Employee>, IFinder<Employee>

这与存储库模式无关——这是关于任何层中的接口(interface),这些接口(interface)看起来像是在语义上共享相同的行为。是否值得为这些操作派生通用接口(interface)并使“子接口(interface)”从它们继承?

至少它会保持方法的签名一致。但这还能给我带来什么其他好处呢? (抛开里氏替换原则)

现在,方法的名称和返回类型无处不在。

我阅读了 Mark Seemann 的关于重用抽象原则的博客,但坦率地说,我并不理解它。也许我只是愚蠢 :) 我还阅读了 Fowler 对 Header Interfaces 的定义。

最佳答案

鉴于此:

interface ICustomer{
    void AddCustomer(Customer toAdd);
    void UpdateCustomer(Customer toUpdate);
    Customer GetById(int customerId);
}

interface IEmployee
{
    void AddEmployee(Employee toBeAdded);
    void UpdateEmployee(Employee toUpdate);
    Employee GetById(int employeeId);       
}

我可能会像这样重新设计它:

interface IRepository<T>
{
    void Add(T toAdd);
    void Update(T toUpdate);
    T GetById(int id);
}

然而,这很可能仍然违反了 Interface Segregation Principle , 更不用说因为它也违反了 Command-Query Responsibility Segregation 模式(不是架构)它也不能既不协变也不逆变。

因此,我的下一步可能是将它们拆分为 Role Interfaces :

interface IAdder<T>
{
    void Add(T toAdd);
}

interface IUpdater<T>
{
    void Update(T toAdd);
}

interface IReader<T>
{
    T GetById(int id);
}

此外,您可能会注意到 IAdder<T>IUpdater<T>在结构上是相同的(它们只是在语义上不同),所以为什么不把它们合二为一:

interface ICommand<T>
{
    void Execute(T item);
}

为了保持一致,您可以重命名 IReader<T>还有:

interface IQuery<T>
{
    T GetById(int id);
}

本质上,您可以将一切缩减为这两个接口(interface),但对于某些人来说,这可能过于抽象,并且携带的语义信息太少。

但是,我认为不可能提供更好的答案,因为前提是有缺陷的。最初的问题是界面应该如何设计,但客户端却遥遥无期。作为APPP channel 11 告诉我们,“客户端 [...] 拥有抽象接口(interface)” - 换句话说,客户端根据需要定义接口(interface)。不应从具体类中提取接口(interface)。

关于这个主题的进一步学习 Material ,这里有几个我的 Pluralsight 类(class):

关于c# - C#中的重用抽象原则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30078347/

相关文章:

javascript - 如何在 JavaScript 中动态命名和创建对象?

ruby - 描述ruby中的类关系

php - Mysqli 抽象,从准备好的语句中获取数组

c# - 在 C# 中使用 xpath,帮助

c# - 单击 notifyIcon 时如何抑制 BalloonTipClicked 事件?

c# - 前导零日期格式 C#

C++ 排序函数

abstraction - 如果数据由 1 个应用程序使用,则使用数据库表而不是仅硬编码简单的数据列表的好处

java - 为什么我们将类声明为抽象类,它只有具体方法?

c# - 使用本地项目引用覆盖 nuget 包引用