在这种情况下,单一责任原则如何避免代码异味?

时间:2019-08-30 02:35:58

标签: c# design-patterns single-responsibility-principle

我是设计模式的新手,我知道单一责任原则的目的,但不确定100%如何避免很多微小的变化。下面是我的示例:

//very crude implementation
public class Journal
{
    private readonly List<string> entries = new List<string>();
    private static int count = 0;

    public void AddEntry(string text)
    {
       entries.Add($"{++count}: {text}");
    }

    public void RemoveEntry(int index)
    {
       entries.RemoveAt(index);
       count--;
    }

    public void SaveToDisk(string filename)
    {
       File.WriteAllText(filename, ToString());
    }
}

我知道SaveToDisk方法不应包含在类中,它应该是专用类,例如PersistenceManager来处理文件保存。

但是为什么我不能将SaveToDisk()类保留在Journal类中?如果有任何新要求,例如将日记保存到云,那么我只需添加一个新方法SaveToCloud(),并且任何依赖的客户端类都可以使用SaveToCloud(),我唯一需要做的修改就是添加{ SaveToCloud()类中的{1}},这很好吗?

已编辑:以下是我的修改版本,请找出所有设计错误:

Journal

2 个答案:

答案 0 :(得分:2)

封装

通过将持久性代码移到单独的PersistenceManager类中,可以保证SaveToDisk()方法不会修改日记帐的任何私有变量,除非使用公共方法和属性。日记。

单一职责

  

但是为什么不能将SaveToDisk()方法保留在Journal类中?如果有任何新要求,例如将日记保存到云,那么我只需添加一个新方法SaveToCloud(),并且任何依赖的客户端类都可以使用SaveToCloud(),我唯一需要做的修改就是在Journal中添加SaveToCloud()课,这完全可以吗?

将日记保存到云中将需要您维护一些额外的状态-连接字符串,api密钥,也许是blob客户端等。您从哪里获得该状态?

  • 您可以将它们全部存储为Journal类中的静态成员
  • 您可以将所有内容作为参数传递给SaveToCloud()方法

将其存储为静态成员是相当有限的,您可以运行并发问题。

每次都将参数传递到SaveToCloud()方法中意味着您需要遍历最初称为SaveToDisk()的每个类,并对其进行更新以存储所需的参数。这些是您要避免的“很多微小变化”。

如果相反,您使用PersistenceManager方法创建了Save()类,则可以将连接字符串等添加到该类,而调用者都不需要更改。

依赖倒置

  

实体必须依赖抽象而不是依赖。

通过在Journal类中将其实现为静态方法,可以消除依赖反转的可能性。想要保存日记的类应将其定义为接口:

public interface IPersistenceManager
{
    void Save(string name);
}

请注意,结尾不会说ToDisk()-呼叫者不必在意保存的日志,只要它是 被保存。然后,当您的要求从磁盘上的存储更改为云上的存储时,您无需对调用方进行任何代码更改。

答案 1 :(得分:0)

Journal类的工作(其唯一职责)是代表期刊。像Journal.saveToDisk()这样的方法存在的问题是它需要的工作不属于该工作,例如确定要使用的文件名,确保在进程中止时不会留下任何不良状态等。 {1}}类不必知道如何处理磁盘。

您已经认识到,这是不良楔形的细边缘。很快,您将需要一个Journal,而Journal.saveToCloud()类也将必须全面了解网络。

在这种情况下,必须将日志工作与磁盘工作分开,以便可以将日志工作放在Journal类中,而磁盘工作则放在其他位置。

常见的解决方案是添加Journal,将日记转换为数据,然后将其保存到磁盘,云或其他任何位置。 byte [] Journal.toByteArray()将执行类似的功能。无论哪种方式,将日记转换为字节序列都是特定于日记的工作,您可以将其放在Journal.writeToStream(Stream target)类中。

是否需要像持久性管理器之类的东西取决于您应用程序的其余部分。