首页 > 其他分享 >面向对象设计的六大原则(SOLID原则)-——开闭原则

面向对象设计的六大原则(SOLID原则)-——开闭原则

时间:2024-03-12 11:23:42浏览次数:19  
标签:Sort sortingStrategy 原则 SOLID void 开闭 class new public

开闭原则(Open-Closed Principle, OCP)是面向对象设计的五大SOLID原则之一。这个原则主张“软件实体(类、模块、函数等)应该对扩展开放,对修改关闭”。也就是说,软件的设计应该允许在不修改原有代码的情况下增加新的功能。这样的设计有助于降低代码的复杂性和维护成本,同时提高系统的可复用性和可维护性。

详细解释

开闭原则强调两点:

  1. 对扩展开放:当需要增加新功能时,应该通过添加新的代码来实现,而不是修改已有的代码。这可以通过使用抽象、接口、继承和多态等面向对象的技术来实现。

  2. 对修改关闭:已有的代码,特别是那些已经经过测试和验证的代码,应该尽量避免修改。这样可以减少引入新bug的风险,同时保持系统的稳定性。

遵循开闭原则可以带来以下好处:

  • 提高可维护性:由于系统对修改关闭,因此可以减少因修改已有代码而引入的错误。
  • 提高可扩展性:系统对扩展开放,使得添加新功能变得更加容易。
  • 降低代码的耦合度:通过抽象和接口来定义系统的行为,可以减少类与类之间的直接依赖,从而降低代码的耦合度。

应用场景及代码示例(C#)

场景1:插件系统

假设我们有一个图像处理系统,我们希望通过插件的方式来添加新的图像处理功能。

代码示例

public interface IImageFilter  
{  
    void ApplyFilter(Image image);  
}  
  
public class BrightnessFilter : IImageFilter  
{  
    public void ApplyFilter(Image image)  
    {  
        // 增加亮度的逻辑  
    }  
}  
  
public class ContrastFilter : IImageFilter  
{  
    public void ApplyFilter(Image image)  
    {  
        // 调整对比度的逻辑  
    }  
}  
  
public class ImageProcessor  
{  
    private List<IImageFilter> filters = new List<IImageFilter>();  
  
    public void AddFilter(IImageFilter filter)  
    {  
        filters.Add(filter);  
    }  
  
    public void ProcessImage(Image image)  
    {  
        foreach (var filter in filters)  
        {  
            filter.ApplyFilter(image);  
        }  
    }  
}  
  
// 使用示例  
var processor = new ImageProcessor();  
processor.AddFilter(new BrightnessFilter());  
processor.AddFilter(new ContrastFilter());  
var image = new Image(); // 假设有一个Image类  
processor.ProcessImage(image);

在这个例子中,ImageProcessor 类对扩展开放,因为我们可以很容易地添加新的滤镜(通过实现 IImageFilter 接口)。同时,它对修改关闭,因为我们不需要修改 ImageProcessor 类来支持新的滤镜。

场景2:策略模式

策略模式是一种常见的设计模式,用于根据不同的情况选择不同的算法或策略。这也符合开闭原则。

代码示例

public interface ISortingStrategy  
{  
    void Sort(List<int> list);  
}  
  
public class BubbleSortStrategy : ISortingStrategy  
{  
    public void Sort(List<int> list)  
    {  
        // 冒泡排序的逻辑  
    }  
}  
  
public class QuickSortStrategy : ISortingStrategy  
{  
    public void Sort(List<int> list)  
    {  
        // 快速排序的逻辑  
    }  
}  
  
public class SortedList  
{  
    private ISortingStrategy sortingStrategy;  
  
    public SortedList(ISortingStrategy sortingStrategy)  
    {  
        this.sortingStrategy = sortingStrategy;  
    }  
  
    public void SetSortingStrategy(ISortingStrategy sortingStrategy)  
    {  
        this.sortingStrategy = sortingStrategy;  
    }  
  
    public void Sort(List<int> list)  
    {  
        sortingStrategy.Sort(list);  
    }  
}  
  
// 使用示例  
var sortedList = new SortedList(new BubbleSortStrategy());  
var numbers = new List<int> { 3, 1, 4, 1, 5, 9 };  
sortedList.Sort(numbers);  
  
// 更换排序策略  
sortedList.SetSortingStrategy(new QuickSortStrategy());  
sortedList.Sort(numbers);
 

在这个例子中,SortedList 类对排序策略的扩展开放,因为我们可以通过实现 ISortingStrategy 接口来添加新的排序算法。同时,它对修改关闭,因为更换排序策略时不需要修改 SortedList 类的内部代码。

当然,开闭原则可以应用于许多不同的场景。以下是一些额外的应用场景示例,以及相应的C#代码:

场景3:日志记录系统

在一个大型系统中,日志记录是非常重要的。你可能想要根据不同的需求添加不同的日志记录器,比如文件日志记录器、控制台日志记录器或数据库日志记录器。通过使用开闭原则,你可以轻松地添加新的日志记录器,而不需要修改现有的日志记录系统。

public interface ILogger  
{  
    void Log(string message);  
}  
  
public class FileLogger : ILogger  
{  
    public void Log(string message)  
    {  
        // 将日志写入文件的逻辑  
    }  
}  
  
public class ConsoleLogger : ILogger  
{  
    public void Log(string message)  
    {  
        Console.WriteLine(message);  
    }  
}  
  
public class LoggingSystem  
{  
    private readonly List<ILogger> loggers = new List<ILogger>();  
  
    public void RegisterLogger(ILogger logger)  
    {  
        loggers.Add(logger);  
    }  
  
    public void Log(string message)  
    {  
        foreach (var logger in loggers)  
        {  
            logger.Log(message);  
        }  
    }  
}  
  
// 使用示例  
var loggingSystem = new LoggingSystem();  
loggingSystem.RegisterLogger(new FileLogger());  
loggingSystem.RegisterLogger(new ConsoleLogger());  
loggingSystem.Log("This is a log message.");

在这个例子中,LoggingSystem 类对日志记录器的扩展开放,因为我们可以实现 ILogger 接口来创建新的日志记录器,并将其注册到系统中。同时,它对修改关闭,因为添加新的日志记录器不需要修改 LoggingSystem 类的代码。

场景4:数据库访问层

在构建应用程序时,你可能需要访问不同的数据库,比如SQL Server、MySQL或Oracle。通过使用开闭原则,你可以设计一个数据库访问层,该层对不同类型的数据库扩展开放,而对现有代码的修改关闭。

代码示例

public interface IDatabase  
{  
    void Connect();  
    void ExecuteQuery(string query);  
    void Close();  
}  
  
public class SqlServerDatabase : IDatabase  
{  
    public void Connect()  
    {  
        // 连接到SQL Server的逻辑  
    }  
  
    public void ExecuteQuery(string query)  
    {  
        // 在SQL Server上执行查询的逻辑  
    }  
  
    public void Close()  
    {  
        // 关闭SQL Server连接的逻辑  
    }  
}  
  
public class MySqlDatabase : IDatabase  
{  
    public void Connect()  
    {  
        // 连接到MySQL的逻辑  
    }  
  
    public void ExecuteQuery(string query)  
    {  
        // 在MySQL上执行查询的逻辑  
    }  
  
    public void Close()  
    {  
        // 关闭MySQL连接的逻辑  
    }  
}  
  
public class DatabaseManager  
{  
    private IDatabase database;  
  
    public DatabaseManager(IDatabase database)  
    {  
        this.database = database;  
    }  
  
    public void PerformQuery(string query)  
    {  
        database.Connect();  
        database.ExecuteQuery(query);  
        database.Close();  
    }  
}  
  
// 使用示例  
var sqlServerDb = new SqlServerDatabase();  
var databaseManager = new DatabaseManager(sqlServerDb);  
databaseManager.PerformQuery("SELECT * FROM Users");  
  
// 切换到MySQL数据库  
var mySqlDb = new MySqlDatabase();  
databaseManager = new DatabaseManager(mySqlDb);  
databaseManager.PerformQuery("SELECT * FROM Users");

在这个例子中,DatabaseManager 类对不同类型的数据库扩展开放,因为我们可以通过实现 IDatabase 接口来创建新的数据库访问类。同时,它对修改关闭,因为切换数据库类型不需要修改 DatabaseManager 类的代码。实际上,在实际应用中,你可能会使用依赖注入框架来动态地注入不同的数据库实现,而不是像示例中那样手动创建和切换它们。

public interface ISortingStrategy { void Sort(List<int> list); } public class BubbleSortStrategy : ISortingStrategy { public void Sort(List<int> list) { // 冒泡排序的逻辑 } } public class QuickSortStrategy : ISortingStrategy { public void Sort(List<int> list) { // 快速排序的逻辑 } } public class SortedList { private ISortingStrategy sortingStrategy; public SortedList(ISortingStrategy sortingStrategy) { this.sortingStrategy = sortingStrategy; } public void SetSortingStrategy(ISortingStrategy sortingStrategy) { this.sortingStrategy = sortingStrategy; } public void Sort(List<int> list) { sortingStrategy.Sort(list); } } // 使用示例 var sortedList = new SortedList(new BubbleSortStrategy()); var numbers = new List<int> { 3, 1, 4, 1, 5, 9 }; sortedList.Sort(numbers); // 更换排序策略 sortedList.SetSortingStrategy(new QuickSortStrategy()); sortedList.Sort(numbers);

标签:Sort,sortingStrategy,原则,SOLID,void,开闭,class,new,public
From: https://www.cnblogs.com/forges/p/18067528

相关文章

  • 16条前端 UI 设计原则
    以一个卡片为例子,逐一按照规则进行优化,左边是原图,右边是经过优化后的设计。规则使用间距对相关元素进行分组一致性确保功能相似外观也相似清晰的视觉层次移除不必要的样式有目的的使用颜色确保界面元素的对比度为3:1确保文本的对比度为4.5:1不要仅仅使用颜色作为指标......
  • 软件设计原则 详解
    软件设计原则是指在软件开发过程中,为了保证软件系统的质量和可维护性,所制定的一系列指导性准则。这些原则旨在帮助开发人员编写出高质量、可扩展、易维护、可复用的软件代码。以下是一些常见的软件设计原则:单一职责原则(SingleResponsibilityPrinciple,SRP):一个类应该只有一个......
  • 在Docker中,构建镜像应该遵循哪些原则?
    构建Docker镜像时,应当遵循以下一系列最佳实践和原则,以确保镜像的高效、安全和易于维护:镜像最小化:选择尽可能小的基础镜像,如AlpineLinux,或者针对特定场景选择轻量级的基础镜像。只安装应用程序运行所必需的软件包和服务,避免无关组件和文件。在构建过程中清理临时文件和构建......
  • mysql8.0 性能优化配置 innodb_buffer_pool_size(配置原则和方式)
    1. BufferPool缓冲池是主内存中的一个区域,InnoDB在访问表和索引数据时会在该区域进行缓存。缓冲池允许直接从内存访问频繁使用的数据,这加快了处理速度。在专用服务器上,通常会将高达80%的物理内存分配给缓冲池。2.简单优化把innodb_buffer_pool_size设置为1G。专用服务......
  • 使用-solidity-开发第一个-以太坊智能合约
    目录目录使用solidity开发第一个以太坊智能合约前言项目源代码最终效果环境搭建智能合约内容Truffle创建项目Truffle编码Truffle打包Truffle部署修改编译器版本0.8.19Truffle测试创建测试文件运行测试命令Dapp命令总结遇到的问题注意Solidity......
  • SOLIDWORKS参数化设计之工程图更新 慧德敏学
    SOLIDWORKS参数化设计不仅仅包括三维模型的参数化设计,还包括工程图的自动更新,由于自动出图仍然存在一定的局限性,不能完美的实现视图的布局及尺寸的标注,因此,现阶段采用的最多的仍然是图纸的更新,也就是利用SOLIDWORKS本身三维与二维模型的关联性,当三维模型尺寸变化之后,二维图纸随着......
  • 系统科学方法及基本原则
    系统科学方法是一种综合性的科学研究方法,它以系统为基本研究对象,通过运用系统的思维,从整体和全局出发,研究系统的内在复杂性。这种方法强调整体观念和综合观念,认为系统是由其各部分组成的,但整体功能大于各部分功能之和。系统科学方法的特征包括整体性、综合性、科学性、动态性和应......
  • 设计原则&模式:六大设计原则
     单一职责原则(SRP:SingleReposibility Principle)定义:一个类或者模块只负责完成一个职责。 里氏替换原则(LSP:LiskovSubstitutionPrinciple)定义:所有使用父类的地方可以使用子类的对象,子类可以扩展父类的功能,但是不能替换父类的功能。如果需要替换父类功能,建议——多用组合,......
  • 设计原则 (6) 迪米特法则
    简介迪米特法则(LawofDemeter,LoD),也称为最少知识原则(PrincipleofLeastKnowledge),是面向对象设计中的一个重要原则。它强调了一个对象应该对其他对象有尽可能少的了解,也就是说,一个对象不应该直接与其它对象进行过多的交互。简而言之,一个对象应该对其他对象保持最少的了解。主要......
  • 设计原则 (5) 依赖倒置原则
    简介依赖倒置原则(DependencyInversionPrinciple,DIP)是面向对象设计中的一个重要原则,它强调了高层模块不应该依赖于低层模块,二者都应该依赖于抽象;而且抽象不应该依赖于具体实现细节,具体实现细节应该依赖于抽象。简而言之,高层模块和低层模块都应该依赖于抽象,而不是依赖于具体的实......