SOLID 设计原则实际上是 Robert C. Martin 提出的五个设计原则。它们分别是:Single Responsibility Principle(单一责任原则)、Open-Close Principle(开闭原则)、Liskov Substitution Principle(里氏替换原则)、Interface Segregation Principle(接口分离原则)、Dependency Inversion Principle(依赖倒置原则)。
看以下代码:
public class Journal
{
private readonly List<string> entries = new List<string>();
private static int count = 0;
public int AddEntry(string text)
{
entries.Add($"{++count}: {text}");
return count;
}
public void RemoveEntry()
{
entries.RemoveAt(count - 1);
count--;
}
public override string ToString()
{
return string.Join(Environment.NewLine, entries);
}
public void Save(string filename)
{
File.WriteAllText(filename, ToString());
}
}
这是一个日记类,我们可以不断往其中添加语句,删除语句,或者输出日记内容。但是我们看到最后一个 Save 方法,它不仅要负责维护自己的私有字段,还要负责自己的持久化,这意味着 Journal 类承担了太多的责任,如果我们想修改 entries 的管理方式,我们要修改这个类,我们想要修改数据的储存方式,还是要修改这个类,这样我们就为修改这个类带来了多个理由。
当然,这种拆分来自于直觉,到底哪些功能属于一类,这个需要多加练习和思考,不一定能一步到位,比如说我们把这个类想象成 MVC 中的 Model,那我们就知道,这个类应该只负责存储和管理 entries,当我们要将这个 model 中的数据 entries 封入协议或者输出到文件中,这样的工作应该是在 Controller 中完成,这样分析我们就能想到持久化的工作并不应该交给 Journal 本身来做。
public class Persistence
{
public void SaveToFile(Journal journal, string filename, bool overwrite = false)
{
if (overwrite || File.Exists(filename))
{
File.WriteAllText(filename, journal.ToString());
}
}
}
Main 函数中的调用如下:
var journal = new Journal();
journal.AddEntry("I cried today");
journal.AddEntry("I ate a bug");
Console.WriteLine(journal);
var persistence = new Persistence();
const string filename = @"../../journal.txt";
persistence.SaveToFile(journal, filename, true);
目前来看 Persistence 依赖于 Journal,只是为了简化代码,在实际工作中应该是传入接口。
看下面的代码:
public class Product
{
public string Name { get; set; }
public Color Color { get; set; }
public Size Size { get; set; }
public Product(string name, Color color, Size size)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
Color = color;
Size = size;
}
}
public enum Size
{
Small,
Medium,
Large,
Huge
}
public enum Color
{
Red,
Green,
Blue
}
public class ProductFilter
{
public IEnumerable<Product> FilterBySize(IEnumerable<Product> products, Size size)
{
foreach (var product in products)
{
if (product.Size == size)
{
yield return product; // yield return 一次返回一个元素 然后保存现场 再次调用时会从现场继续执行
}
}
}
public IEnumerable<Product> FilterByColor(IEnumerable<Product> products, Color color)
{
foreach (var product in products)
{
if (product.Color == color)
{
yield return product;
}
}
}
public IEnumerable<Product> FilterByColorAndSize(IEnumerable<Product> products, Color color, Size size)
{
foreach (var product in products)
{
if (product.Color == color && product.Size == size)
{
yield return product;
}
}
}
}