一般网站建设用什么样的代码,汕头网站制作专业,湖北建设执业注册中心网站,里水九江网站建设一.概述SOLID五大原则使我们能够管理解决大多数软件设计问题。由Robert C. Martin在20世纪90年代编写了这些原则。这些原则为我们提供了从紧耦合的代码和少量封装转变为适当松耦合和封装业务实际需求的结果方法。使用这些原则#xff0c;我们可以构建一个具有整洁#xff0c;… 一.概述 SOLID五大原则使我们能够管理解决大多数软件设计问题。由Robert C. Martin在20世纪90年代编写了这些原则。这些原则为我们提供了从紧耦合的代码和少量封装转变为适当松耦合和封装业务实际需求的结果方法。使用这些原则我们可以构建一个具有整洁可读且易于维护的代码应用程序。 SOLID缩写如下 SRP 单一责任原则OCP 开放/封闭原则LSP 里氏替换原则ISP 接口分离原则DIP 依赖反转原则 1.单一责任原则SRP 一个类承担的责任在理想情况下应该是多少个呢答案是一个。这个责任是围绕一个核心任务构建不是简化的意思。通过暴露非常有限的责任使这个类与系统的交集更小。 (1) 演示违反了单一责任原则原因是顾客类中承担了太多无关的责任。 /// summary/// 顾客类所有实现/// /summarypublic class Cliente {public int ClienteId { get; set; }public string Nome { get; set; }public string Email { get; set; }public string CPF { get; set; }public DateTime DataCadastro { get; set; }public string AdicionarCliente() {//顾客信息验证if (!Email.Contains())return Cliente com e-mail inválido;if (CPF.Length ! 11)return Cliente com CPF inválido;//保存顾客信息using (var cn new SqlConnection()) {var cmd new SqlCommand(); cn.ConnectionString MinhaConnectionString; cmd.Connection cn; cmd.CommandType CommandType.Text; cmd.CommandText INSERT INTO CLIENTE (NOME, EMAIL CPF, DATACADASTRO) VALUES (nome, email, cpf, dataCad)); cmd.Parameters.AddWithValue(nome, Nome); cmd.Parameters.AddWithValue(email, Email); cmd.Parameters.AddWithValue(cpf, CPF); cmd.Parameters.AddWithValue(dataCad, DataCadastro); cn.Open(); cmd.ExecuteNonQuery(); }//发布邮件var mail new MailMessage(empresaempresa.com, Email);var client new SmtpClient { Port 25, DeliveryMethod SmtpDeliveryMethod.Network, UseDefaultCredentials false, Host smtp.google.com }; mail.Subject Bem Vindo.; mail.Body Parabéns! Você está cadastrado.; client.Send(mail);return Cliente cadastrado com sucesso!; } } (2) 解决方案使用单一责任原则每个类只负责自己的业务。 /// summary/// 顾客实体/// /summarypublic class Cliente {public int ClienteId { get; set; }public string Nome { get; set; }public string Email { get; set; }public string CPF { get; set; }public DateTime DataCadastro { get; set; }/// summary/// 顾客信息验证/// /summary/// returns/returnspublic bool IsValid() {return EmailServices.IsValid(Email) CPFServices.IsValid(CPF); } }/// summary/// 保存顾客信息/// /summarypublic class ClienteRepository {/// summary/// 保存/// /summary/// param namecliente要保存的顾客实体/parampublic void AdicionarCliente(Cliente cliente) {using (var cn new SqlConnection()) {var cmd new SqlCommand(); cn.ConnectionString MinhaConnectionString; cmd.Connection cn; cmd.CommandType CommandType.Text; cmd.CommandText INSERT INTO CLIENTE (NOME, EMAIL CPF, DATACADASTRO) VALUES (nome, email, cpf, dataCad)); cmd.Parameters.AddWithValue(nome, cliente.Nome); cmd.Parameters.AddWithValue(email, cliente.Email); cmd.Parameters.AddWithValue(cpf, cliente.CPF); cmd.Parameters.AddWithValue(dataCad, cliente.DataCadastro); cn.Open(); cmd.ExecuteNonQuery(); } } }/// summary/// CPF服务/// /summarypublic static class CPFServices {public static bool IsValid(string cpf) {return cpf.Length 11; } }/// summary/// 邮件服务/// /summarypublic static class EmailServices {public static bool IsValid(string email) {return email.Contains(); }public static void Enviar(string de, string para, string assunto, string mensagem) {var mail new MailMessage(de, para);var client new SmtpClient { Port 25, DeliveryMethod SmtpDeliveryMethod.Network, UseDefaultCredentials false, Host smtp.google.com }; mail.Subject assunto; mail.Body mensagem; client.Send(mail); } }/// summary/// 客户服务程序调用入口/// /summarypublic class ClienteService {public string AdicionarCliente(Cliente cliente) {//先验证if (!cliente.IsValid())return Dados inválidos;//保存顾客var repo new ClienteRepository(); repo.AdicionarCliente(cliente);//邮件发送 EmailServices.Enviar(empresaempresa.com, cliente.Email, Bem Vindo, Parabéns está Cadastrado);return Cliente cadastrado com sucesso; } } 2. 开放/封闭原则OCP 类应该是可以可扩展的可以用作构建其他相关新功能这叫开放。但在实现相关功能时不应该修改现有代码因为已经过单元测试运行正常这叫封闭。 (1) 演示违反了开放/封闭原则原因是每次增加新形状时需要改变AreaCalculator 类的TotalArea方法例如开发后期又增加了圆形形状。 /// summary/// 长方形实体/// /summarypublic class Rectangle {public double Height { get; set; }public double Width { get; set; } }/// summary/// 圆形/// /summarypublic class Circle {/// summary/// 半径/// /summarypublic double Radius { get; set; } }/// summary/// 面积计算 /// /summarypublic class AreaCalculator {public double TotalArea(object[] arrObjects) {double area 0; Rectangle objRectangle; Circle objCircle;foreach (var obj in arrObjects) {if (obj is Rectangle) { objRectangle (Rectangle)obj; area objRectangle.Height * objRectangle.Width; }else { objCircle (Circle)obj; area objCircle.Radius * objCircle.Radius * Math.PI; } }return area; } } (2) 解决方案使用开放/封闭原则每次增加新形状时(开放)不需要修改TotalArea方法(封闭) /// summary/// 形状抽象类/// /summarypublic abstract class Shape {/// summary/// 面积计算/// /summary/// returns/returnspublic abstract double Area(); }/// summary/// 长方形/// /summarypublic class Rectangle : Shape {public double Height { get; set; }public double Width { get; set; }public override double Area() {return Height * Width; } }/// summary/// 圆形/// /summarypublic class Circle : Shape {public double Radius { get; set; }public override double Area() {return Radius * Radius * Math.PI; } }/// summary/// 面积计算/// /summarypublic class AreaCalculator {public double TotalArea(Shape[] arrShapes) {double area 0;foreach (var objShape in arrShapes) { area objShape.Area(); }return area; } } 3.里氏替换原则LSP 这里也涉及到了类的继承也适用于接口。子类可以替换它们的父类。里氏替换原则常见的代码问题是使用虚方法在父类定义虚方法时要确保该方法里没有任何私有成员。 (1) 演示违反了里氏替换原则, 原因是不能使用ReadOnlySqlFile子类替代SqlFile父类。 /// summary/// sql文件类 读取、保存 /// /summarypublic class SqlFile {public string FilePath { get; set; }public string FileText { get; set; }public virtual string LoadText() {/* Code to read text from sql file */return ..; }public virtual void SaveText() {/* Code to save text into sql file */ } }/// summary/// 开发途中增加了sql文件只读类/// /summarypublic class ReadOnlySqlFile : SqlFile {public override string LoadText() {/* Code to read text from sql file */return ..; }public override void SaveText() {/* Throw an exception when app flow tries to do save. */ throw new IOException(Cant Save); } }public class SqlFileManager {/// summary/// 集合中存在两种类SqlFile和ReadOnlySqlFile/// /summarypublic ListSqlFile lstSqlFiles { get; set; }/// summary/// 读取/// /summary/// returns/returnspublic string GetTextFromFiles() { StringBuilder objStrBuilder new StringBuilder();foreach (var objFile in lstSqlFiles) { objStrBuilder.Append(objFile.LoadText()); }return objStrBuilder.ToString(); }/// summary/// 保存/// /summarypublic void SaveTextIntoFiles() {foreach (var objFile in lstSqlFiles) {//检查当前对象是ReadOnlySqlFile类,跳过调用SaveText()方法 if (!(objFile is ReadOnlySqlFile)) { objFile.SaveText(); } } } } (2) 解决方案使用里氏替换原则子类可以完全代替父类 public interface IReadableSqlFile {string LoadText(); }public interface IWritableSqlFile {void SaveText(); }public class ReadOnlySqlFile : IReadableSqlFile {public string FilePath { get; set; }public string FileText { get; set; }public string LoadText() {/* Code to read text from sql file */return ; } }public class SqlFile : IWritableSqlFile, IReadableSqlFile {public string FilePath { get; set; }public string FileText { get; set; }public string LoadText() {/* Code to read text from sql file */return ; }public void SaveText() {/* Code to save text into sql file */ } }public class SqlFileManager {public string GetTextFromFiles(ListIReadableSqlFile aLstReadableFiles) { StringBuilder objStrBuilder new StringBuilder();foreach (var objFile in aLstReadableFiles) {//ReadOnlySqlFile的LoadText实现 objStrBuilder.Append(objFile.LoadText()); }return objStrBuilder.ToString(); }public void SaveTextIntoFiles(ListIWritableSqlFile aLstWritableFiles) {foreach (var objFile in aLstWritableFiles) {//SqlFile的SaveText实现 objFile.SaveText(); } } } 4.接口分离原则ISP 接口分离原则是解决接口臃肿的问题建议接口保持最低限度的函数。永远不应该强迫客户端依赖于它们不用的接口。 (1) 演示违反了接口分离原则。原因是Manager无法处理任务同时没有人可以将任务分配给Manager因此WorkOnTask方法不应该在Manager类中。 /// summary/// 领导接口/// /summarypublic interface ILead {//创建任务void CreateSubTask();//分配任务void AssginTask();//处理指定任务void WorkOnTask(); }/// summary/// 团队领导/// /summarypublic class TeamLead : ILead {public void AssginTask() {//Code to assign a task. }public void CreateSubTask() {//Code to create a sub task }public void WorkOnTask() {//Code to implement perform assigned task. } }/// summary/// 管理者/// /summarypublic class Manager : ILead {public void AssginTask() {//Code to assign a task. }public void CreateSubTask() {//Code to create a sub task. }public void WorkOnTask() {throw new Exception(Manager cant work on Task); } } (2) 解决方案使用接口分离原则 /// summary/// 程序员角色/// /summarypublic interface IProgrammer {void WorkOnTask(); }/// summary/// 领导角色/// /summarypublic interface ILead {void AssignTask();void CreateSubTask(); }/// summary/// 程序员执行任务/// /summarypublic class Programmer : IProgrammer {public void WorkOnTask() {//code to implement to work on the Task. } }/// summary/// 管理者可以创建任务、分配任务/// /summarypublic class Manager : ILead {public void AssignTask() {//Code to assign a Task }public void CreateSubTask() {//Code to create a sub taks from a task. } }/// summary/// 团队领域可以创建任务、分配任务、执行执行/// /summarypublic class TeamLead : IProgrammer, ILead {public void AssignTask() {//Code to assign a Task }public void CreateSubTask() {//Code to create a sub task from a task. }public void WorkOnTask() {//code to implement to work on the Task. } } 5. 依赖反转原则DIP 依赖反转原则是对程序的解耦。高级模块/类不应依赖于低级模块/类两者都应该依赖于抽象。意思是当某个类被外部依赖时就需要把该类抽象成一个接口。接口如何变成可调用的实例呢实践中多用依赖注入模式。这个依赖反转原则在DDD中得到了很好的运用实践(参考前三篇)。 (1) 演示违反了依赖反转原则。原因是每当客户想要引入新的Logger记录形式时我们需要通过添加新方法来改变ExceptionLogger类。这里错误的体现了高级类 ExceptionLogger直接引用低级类FileLogger和DbLogger来记录异常。 /// summary/// 数据库日志类/// /summarypublic class DbLogger {//写入日志public void LogMessage(string aMessage) {//Code to write message in database. } }/// summary/// 文件日志类/// /summarypublic class FileLogger {//写入日志public void LogMessage(string aStackTrace) {//code to log stack trace into a file. } }public class ExceptionLogger {public void LogIntoFile(Exception aException) { FileLogger objFileLogger new FileLogger(); objFileLogger.LogMessage(GetUserReadableMessage(aException)); }public void LogIntoDataBase(Exception aException) { DbLogger objDbLogger new DbLogger(); objDbLogger.LogMessage(GetUserReadableMessage(aException)); }private string GetUserReadableMessage(Exception ex) {string strMessage string.Empty;//code to convert Exceptions stack trace and message to user readable format. return strMessage; } }public class DataExporter {public void ExportDataFromFile() {try {//code to export data from files to database. }catch (IOException ex) {new ExceptionLogger().LogIntoDataBase(ex); }catch (Exception ex) {new ExceptionLogger().LogIntoFile(ex); } } } (2) 解决方案使用依赖反转原则这里演示没有用依赖注入。 public interface ILogger {void LogMessage(string aString); }/// summary/// 数据库日志类/// /summarypublic class DbLogger : ILogger {//写入日志public void LogMessage(string aMessage) {//Code to write message in database. } }/// summary/// 文件日志类/// /summarypublic class FileLogger : ILogger {//写入日志public void LogMessage(string aStackTrace) {//code to log stack trace into a file. } }public class ExceptionLogger {private ILogger _logger;public ExceptionLogger(ILogger aLogger) {this._logger aLogger; }//可以与这些日志类达到松散耦合public void LogException(Exception aException) {string strMessage GetUserReadableMessage(aException);this._logger.LogMessage(strMessage); }private string GetUserReadableMessage(Exception aException) {string strMessage string.Empty;//code to convert Exceptions stack trace and message to user readable format. return strMessage; } }public class DataExporter {public void ExportDataFromFile() { ExceptionLogger _exceptionLogger;try {//code to export data from files to database. }catch (IOException ex) { _exceptionLogger new ExceptionLogger(new DbLogger()); _exceptionLogger.LogException(ex); }catch (Exception ex) { _exceptionLogger new ExceptionLogger(new FileLogger()); _exceptionLogger.LogException(ex); } } } 参考文献 SOLID原则简介原文地址https://www.cnblogs.com/MrHSR/p/10912615.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com