C#的五大设计原则-solid原则

什么是C#的五大设计原则,我们用人话来解释一下,希望小伙伴们能学会:

好的,让我们以一种幽默的方式来解释C#的五大设计原则(SOLID):

单一职责原则(Single Responsibility Principle, SRP):别让一个类做得像瑞士军刀一样样样都干,它会累趴下的。让每个类专注于一件事,成就一个小专家!

开闭原则(Open/Closed Principle, OCP):代码就像房子一样,应该允许你随时装修,但不要让你每次都得拆墙。你的类应该开放给扩展,关闭给修改。装修可以,但别动地基。

里氏替换原则(Liskov Substitution Principle, LSP):如果它看起来像鸭子,游起来像鸭子,叫起来也像鸭子,那它就应该是个鸭子。子类应该能完全替代父类,就像鸭子替代鸭子一样。

接口隔离原则(Interface Segregation Principle, ISP):不要逼用户点一堆不想要的菜,分开菜单让他们点自己喜欢的。让接口精简,用户用起来才不会吐槽你。

依赖倒置原则(Dependency Inversion Principle, DIP):别总想着亲自动手干活,雇个专业的帮你干!高层模块不应该依赖低层模块,而应该依赖于抽象。让专业的人做专业的事,你只需要指挥就好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1. 单一职责原则(SRP - Single Responsibility Principle)

不使用SRP:

public class UserService
{
    public void RegisterUser(string name, string email)
    {
        // 保存用户到数据库
        SaveUserToDatabase(name, email);

        // 发送欢迎邮件
        SendWelcomeEmail(email);
    }

    private void SaveUserToDatabase(string name, string email)
    {
        // 代码逻辑
    }

    private void SendWelcomeEmail(string email)
    {
        // 代码逻辑
    }
}

在这个示例中,UserService类同时处理用户注册和发送邮件,职责不单一,导致类的复杂性增加,不利于维护和扩展。

使用SRP:

public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class UserRepository
{
    public void AddUser(User user) { /* 代码 */ }
    public User GetUserByEmail(string email) { /* 代码 */ }
}

public class EmailService
{
    public void SendEmail(User user) { /* 代码 */ }
}

public class UserService
{
    private readonly UserRepository _userRepository;
    private readonly EmailService _emailService;

    public UserService(UserRepository userRepository, EmailService emailService)
    {
        _userRepository = userRepository;
        _emailService = emailService;
    }

    public void RegisterUser(User user)
    {
        _userRepository.AddUser(user);
        _emailService.SendEmail(user);
    }
}

在这个示例中,职责被分离到了不同的类中,UserService只负责协调这些操作,使代码更清晰、可维护。

2. 开闭原则(OCP - Open/Closed Principle)

不使用OCP:

public class Shape
{
    public double Radius { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }

    public double GetArea(string shapeType)
    {
        if (shapeType == "Circle")
        {
            return Math.PI * Radius * Radius;
        }
        else if (shapeType == "Rectangle")
        {
            return Width * Height;
        }
        else
        {
            return 0;
        }
    }
}

在这个示例中,添加新的形状类型需要修改GetArea方法的代码,违反了开闭原则。

使用OCP:

public abstract class Shape
{
    public abstract double Area();
}

public class Circle : Shape
{
    public double Radius { get; set; }
    public override double Area() => Math.PI * Radius * Radius;
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
    public override double Area() => Width * Height;
}

在这个示例中,通过扩展Shape类,我们可以添加新的形状而不需要修改现有的代码,符合开闭原则。

3. 里氏替换原则(LSP - Liskov Substitution Principle)

不使用LSP:

public class Rectangle
{
    public virtual double Width { get; set; }
    public virtual double Height { get; set; }
    public double Area() => Width * Height;
}

public class Square : Rectangle
{
    public override double Width
    {
        set { base.Width = base.Height = value; }
    }

    public override double Height
    {
        set { base.Width = base.Height = value; }
    }
}

在这个示例中,Square类违反了里氏替换原则,因为WidthHeight的行为在子类中改变了。

使用LSP:

public abstract class Shape
{
    public abstract double Area();
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
    public override double Area() => Width * Height;
}

public class Square : Shape
{
    public double SideLength { get; set; }
    public override double Area() => SideLength * SideLength;
}

在这个示例中,RectangleSquare都正确实现了ShapeArea方法,符合里氏替换原则。

4. 接口隔离原则(ISP - Interface Segregation Principle)

不使用ISP:

public interface IWorker
{
    void Work();
    void Eat();
}

public class Worker : IWorker
{
    public void Work() { /* 代码逻辑 */ }
    public void Eat() { /* 代码逻辑 */ }
}

public class Robot : IWorker
{
    public void Work() { /* 代码逻辑 */ }
    public void Eat()
    {
        throw new NotImplementedException();
    }
}

在这个示例中,Robot类必须实现它不需要的Eat方法,导致接口不符合实际需求。

使用ISP:

public interface IWorkable
{
    void Work();
}

public interface IEatable
{
    void Eat();
}

public class Worker : IWorkable, IEatable
{
    public void Work() { /* 代码逻辑 */ }
    public void Eat() { /* 代码逻辑 */ }
}

public class Robot : IWorkable
{
    public void Work() { /* 代码逻辑 */ }
}

在这个示例中,IWorkableIEatable接口被分离,Robot类只实现了需要的接口,符合接口隔离原则。

5. 依赖倒置原则(DIP - Dependency Inversion Principle)

不使用DIP:

public class DatabaseLogger
{
    public void Log(string message)
    {
        // 记录日志到数据库
    }
}

public class UserService
{
    private readonly DatabaseLogger _logger = new DatabaseLogger();

    public void RegisterUser(string name, string email)
    {
        // 记录日志
        _logger.Log("Registering user " + name);

        // 其他代码
    }
}

在这个示例中,UserService类直接依赖于具体的DatabaseLogger实现,违反了依赖倒置原则。

使用DIP:

public interface ILogger
{
    void Log(string message);
}

public class DatabaseLogger : ILogger
{
    public void Log(string message)
    {
        // 记录日志到数据库
    }
}

public class FileLogger : ILogger
{
    public void Log(string message)
    {
        // 记录日志到文件
    }
}

public class UserService
{
    private readonly ILogger _logger;

    public UserService(ILogger logger)
    {
        _logger = logger;
    }

    public void RegisterUser(string name, string email)
    {
        // 记录日志
        _logger.Log("Registering user " + name);

        // 其他代码
    }
}

在这个示例中,UserService类依赖于ILogger接口,而不是具体的实现,符合依赖倒置原则,使得代码更加灵活和可扩展。

总结对比

  • 单一职责原则(SRP): 通过分离职责减少类的复杂度,使代码更易读和维护。不使用SRP会导致类变得庞大,职责不清,维护困难。
  • 开闭原则(OCP): 通过扩展来增加新功能,而不是修改已有代码,提高了代码的稳定性和可扩展性。不使用OCP会导致每次增加新功能都需要修改已有代码,增加了出错的风险。
  • 里氏替换原则(LSP): 确保子类可以替代基类而不会导致程序出错,保证继承的正确性。不使用LSP会导致子类行为不一致,破坏程序的稳定性。
  • 接口隔离原则(ISP): 通过细化接口,使得类只依赖于需要的接口,减少不必要的依赖关系。不使用ISP会导致类实现不需要的接口方法,增加了代码的复杂度。
  • 依赖倒置原则(DIP): 通过依赖于抽象(接口或抽象类)而不是具体实现,降低模块之间的耦合,提高代码的灵活性和可测试性。不使用DIP会导致类之间的高耦合,难以进行单元测试和模块替换。

通过遵循SOLID原则,可以显著提高代码的可维护性、可扩展性和灵活性,使开发和维护变得更加高效。

相关推荐

  1. 设计模式】SOLID设计原则

    2024-07-09 22:18:03       27 阅读
  2. 设计时候面向对象遵循原则 SOLID

    2024-07-09 22:18:03       53 阅读
  3. C++】【设计模式原则

    2024-07-09 22:18:03       38 阅读
  4. C++中设计原则

    2024-07-09 22:18:03       20 阅读
  5. 设计模式】02-SOLID 设计原则

    2024-07-09 22:18:03       50 阅读
  6. C++|设计模式(〇)|设计模式原则

    2024-07-09 22:18:03       28 阅读
  7. C#入门理解设计模式6原则

    2024-07-09 22:18:03       33 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-09 22:18:03       50 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-09 22:18:03       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-09 22:18:03       43 阅读
  4. Python语言-面向对象

    2024-07-09 22:18:03       54 阅读

热门阅读

  1. 【Rust入门】猜数游戏

    2024-07-09 22:18:03       23 阅读
  2. NVIDIA H100 Tensor Core GPU摘要

    2024-07-09 22:18:03       17 阅读
  3. 释放计算潜能:Mojo模型与分布式训练的融合之道

    2024-07-09 22:18:03       17 阅读
  4. 环境构建大师:精通Conda中的conda create命令

    2024-07-09 22:18:03       19 阅读
  5. 我的创作4096天纪念日

    2024-07-09 22:18:03       19 阅读
  6. python 高级技巧 0706

    2024-07-09 22:18:03       16 阅读
  7. 前端面试基础html/js/css

    2024-07-09 22:18:03       17 阅读
  8. crontab定时任务不执行原因排查

    2024-07-09 22:18:03       16 阅读
  9. RTOS系统 -- ARM Cortex-M4 RPMSG之通道初始化函数

    2024-07-09 22:18:03       16 阅读
  10. shell中不常见的命令

    2024-07-09 22:18:03       20 阅读
  11. 直播APP开发源码搭建

    2024-07-09 22:18:03       17 阅读
  12. 自己写个简单的vite插件

    2024-07-09 22:18:03       23 阅读
  13. ROS melodic版本卸载---Ubuntu18.04

    2024-07-09 22:18:03       17 阅读
  14. Ubuntu手动编译源码安装Python

    2024-07-09 22:18:03       17 阅读