面向对象开发 SOLID 设计原则(C#举例)

2024-02-23 17:48

本文主要是介绍面向对象开发 SOLID 设计原则(C#举例),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 基本定义
    • 细则说明
        • SRP:单一职责原则
        • OCP:开闭原则
        • LSP:里式替换原则
        • ISP:接口隔离原则
        • DIP:依赖反转原则
    • 程序示例
        • SRP:单一职责原则
        • OCP:开闭原则
        • LSP:里式替换原则
        • ISP:接口隔离原则
        • DIP:依赖反转原则


基本定义

S: Single Responsibility Principle(SRP),单一职责原则。

A class or module should have a single reponsibility.
一个类或模块,只负责完成一项职责。

O: Open Closed Principle(OCP),开闭原则

software entities (modules, classes, functions, etc.) should be open for extension, but closed for modification.
软件实体(模块,类,方法等)应该对扩展开放,对修改关闭。

L: Liskov Substitution Principle(LSP),里式替换原则

Functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it.
子类对象可以替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏。

I: Interface Segregation Principle(ISP),接口隔离原则

Clients should not be forced to depend upon interfaces that they do not use.
客户端不应该被强制依赖它不需要的接口。

D: Dependency Inversion Principle(DIP),依赖反转原则

High-level modules shouldn’t depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn’t depend on details. Details depend on abstrations.
高层模块不要依赖于低层模块,高层模块和低层模块应该通过抽象来相互依赖,另外,抽象不要依赖具体实现细节,具体实现细节依赖抽象。


细则说明

SRP:单一职责原则

该原则建议设计功能合理的类,避免将不相关的功能耦合在一起形成一个大而全的类,来提高单个类的内聚性,同时也由于功能简单而减少相互依赖,进而减少了耦合性。

当然,也不是要将类拆分的越细越好,而是需要根据业务来调整,其中有一些问题可以帮助来判断是否一个类设计的过大:

  1. 类中的代码行数、函数或者属性过多
  2. 当前类跟较多类有依赖关系
  3. 私有方法过多
  4. 很难定位类的功能,或者很难给类起一个合适的名字
  5. 类中太多的方法集中操作类中某几个属性
OCP:开闭原则

该原则目标是在实现一个高扩展的类,即以最小的修改代价来完成新功能的开发,避免因为新功能对原有功能或程序产生较大的影响。

在设计时候考虑到未来需求变化的扩展性,提高扩展意识、抽象意识、封装意识是写出好扩展性代码的重要条件,有一些提高代码扩展性的思路:

  1. 使用多态
  2. 依赖注入
  3. 基于接口而非实现编程
  4. 学习使用设计模式(装饰器、策略等)
LSP:里式替换原则

该原则目标是保留父类原有的行为约定,即子类可以根据自己的功能约定实现自己的逻辑,但子类的实现不能修改父类原来的行为约定。

常见的行为约定包括:

  1. 函数声明要实现功能
  2. 对输入、输出、异常的约定
  3. 注释种罗列的任何特殊说明
ISP:接口隔离原则

该原则的目标是建立一个功能纯粹的接口,对于只是被部分调用者使用的功能需要从接口中拆分出来,避免让不需要该功能的调用者依赖。

使用接口隔离是需要在接口层面定义更细的粒度,使得程序更灵活、易扩展、易复用。

DIP:依赖反转原则

该原则一般用于指导框架层面的设计,即将程序的控制权由框架来完成(反转给了框架),避免程序员自己通过面向过程思想实现整个程序。


程序示例

SRP:单一职责原则
// 用户信息类
public class UserInfo {
//author: suoxd123@126.comprivate long Id;private String name; //姓名private String email;private String phone;private long lastLoginTime;private String province; // 省private String city; // 市private String region; // 区 private String address; // 详细地址
}

如果该类信息每次使用都只是用于显示,直接这么设计没问题。
如果业务需要地址信息经常被其它模块单独使用,可以考虑将地址信息(province, city, region, address)拆分出来,然后这里引用
如果业务需要对账号信息单独使用,可以考虑将账户信息(name, email, phone)拆分出来,然后这里引用

OCP:开闭原则
//author: suoxd123@126.com
public interface IRun { //...     }
public class TwoLegRun : IRun { //...     }
public class FourLegRun : IRun { //...    }
public class Demo {private IRun animal; // 基于接口而非实现编程public Demo (IRun animal) { // 依赖注入this.animal = animal;}
}

如果后期增加一个单腿跑的功能,当前的设计修改就不多,只需要继承接口IRun后,直接调用即可。
相反,如果不用当前的设计,而是基于不同参数(几条腿)来实现不同的行为,那改函数就比较臃肿,而且新功能引入的改动可能会对原有功能稳定程序带来风险。

LSP:里式替换原则
//author: suoxd123@126.com
public class Run { public virtual void moveOn(int speed){}
}
public class SlowRun : Run { public override void moveOn(int speed){}
}

SlowRun中的MoveOn方法跟父类中的方法在输入输出上完全一致,即对于父类Run使用的场景,如果替换成子类SlowRun也完全可以调用

ISP:接口隔离原则
//author: suoxd123@126.com
public interface IRun{void Moveon(int speed);}
public interface IFly{void Flyon(int speed);}public class Sparrow:IRun, IFly { public void Moveon(int speed){}public void Flyon(int speed){}
}public class Dog:IRun { public void Moveon(int speed){}
}

如上定义了IRun和IFly两个接口,因此可以分别对于具有IRun和IFly能力的动物进行继承和实现。
相反,如果定义一个接口中含有Moveon和Flyon的函数,那么在Dog中对Flyon的实现就容易让人误解。

DIP:依赖反转原则
public class Demo {public static void main(String args[]) {Runner runner = new Runner(); //创建对象Sports sport = new sport(runner);//依赖注入sport.showInfo();}
}

上面程序展示了依赖注入,即对于对象的使用不是在程序内部实例化,而是通过构造函数或者参数的方式,对实例对象进行传递和调用。

//author: suoxd123@126.compublic class Runner{public static void Run(){// ...   }  }public static void main(String[] args){//这部分逻辑可以放到框架中Run();}}//=================================
// 上面:程序执行流程是由程序开发者来启动和执行
// 下面:程序反转给了框架,开发者仅需要实现功能
//=================================public interface Runner{void Run();}public class Marathon : Runner{public void Run(){//...}}public class CrossCountry : Runner{public void Run(){//...}}}public class AutoApplication{private static List<Runner> runnerList = new List<Runner>();public static void register(Runner runner){runnerList.Add(runner);}public static void main(String[] args){foreach (Runner runner in runnerList){runner.Run();}}}

程序中间的注释已经表示了,上面的情况,开发者自己按流程进行开发,容易成为面向过程的方式进行开发。
对比,下面的情况,开发者只需要实现程序的功能,具体的调用和实例化可以有框架完成

这篇关于面向对象开发 SOLID 设计原则(C#举例)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/739418

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry