翻译、参考:https://www.dotnetcurry.com/software-gardening/1148/solid-single-responsibility-principle |
在用面向对象编程很多年后,我发现很多程序员总是违反这个原则。
是的,我们写类和方法,企图以面向过程的方式将逻辑写到同一个方法内,而不是把它们拆分成很多单一的类,每个只负责做一件事。
这里有一些典型的示例代码
public class CsvFileProcessor { public void Process(string filename) { TextReader tr = new StreamReader(filename); tr.ReadToEnd(); tr.Close(); var conn = new SqlConnection("server=(local);integrated security=sspi;database=SRP"); conn.Open(); string[] lines = tr.ToString().Split(new string[] {@"\r\l"}, StringSplitOptions.RemoveEmptyEntries); foreach( string line in lines) { string[] columns = line.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries); var command = conn.CreateCommand(); command.CommandText = "INSERT INTO People (FirstName, LastName, Email) VALUES (@FirstName, @LastName, @Email)"; command.Parameters.AddWithValue("@FirstName", columns[0]); command.Parameters.AddWithValue("@LastName", columns[1]); command.Parameters.AddWithValue("@Email", columns[2]); command.ExecuteNonQuery(); } conn.Close(); } }
这个类做了几件事?一件?两件?三件?或者更多?
我们用 ParseCsv() 这个方法 CSV文件转换为一行一行的 ,但是StoreCsvData() 这个方法是将行转换为一列一列的。
解决这个问题的方法是 采用ContactDTO 来储存每一行的数据。
下一步是添加DTO,但我将跳过一个步骤,并将每个方法分解到它自己的类中。
但是我同时也预想到一些问题,如果这些数据不是来自CSV呢?如果它来自XML、JSON或者其它数据格式怎么办?
你用 接口 解决了这个问题
public interface IContactDataProvider { string Read(); } public interface IContactParser { IList<ContactDTO> Parse(string contactList); } public interface IContactWriter { void Write(IList<ContactDTO> contactData); } public class ContactProcessor { public void Process(IContactDataProvider cdp, IContactParser cp, IContactWriter cw) { var providedData = cdp.Read(); var parsedData = cp.Parse(providedData); cw.Write(parsedData); } } public class CSVContactDataProvider : IContactDataProvider { private readonly string _filename; public CSVContactDataProvider(string filename) { _filename = filename; } public string Read() { TextReader tr = new StreamReader(_filename); tr.ReadToEnd(); tr.Close(); return tr.ToString(); } } public class CSVContactParser : IContactParser { public IList<ContactDTO> Parse(string csvData) { IList<ContactDTO> contacts = new List<ContactDTO>(); string[] lines = csvData.Split(new string[] { @"\r\l" }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) { string[] columns = line.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); var contact = new ContactDTO { FirstName = columns[0], LastName = columns[1], Email = columns[2] }; contacts.Add(contact); } return contacts; } } public class ADOContactWriter : IContactWriter { public void Write(IList<ContactDTO> contacts) { var conn = new SqlConnection("server=(local);integrated security=sspi;database=SRP"); conn.Open(); foreach (var contact in contacts) { var command = conn.CreateCommand(); command.CommandText = "INSERT INTO People (FirstName, LastName, Email) VALUES (@FirstName, @LastName, @Email)"; command.Parameters.AddWithValue("@FirstName", contact.FirstName); command.Parameters.AddWithValue("@LastName", contact.LastName); command.Parameters.AddWithValue("@Email", contact.Email); command.ExecuteNonQuery(); } conn.Close(); } } public class ContactDTO { public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } }