当前位置: 首页 > news >正文

掌握 C# 设计模式:从基础到依赖注入

设计模式是一种可以在开发中重复使用的解决方案,能够提高代码的可维护性、扩展性和复用性。C# 中常见的设计模式包括单例模式、工厂模式、观察者模式、策略模式等。本文将介绍这些常见的设计模式,并探讨 SOLID 原则和依赖注入(Dependency Injection)的重要性。


1. 常见设计模式

单例模式(Singleton)

单例模式 确保一个类只有一个实例,并提供全局访问点。它在需要共享资源或控制全局状态的情况下非常有用。

public class Singleton
{private static Singleton instance;private static readonly object lockObj = new object();private Singleton() { }public static Singleton Instance{get{lock (lockObj){if (instance == null){instance = new Singleton();}return instance;}}}
}

在上面的例子中,Singleton 类通过静态 Instance 属性保证全局唯一性,并使用双重锁定确保线程安全。

工厂模式(Factory)

工厂模式 提供了一种创建对象的接口,而不是直接实例化类。它将对象的创建与业务逻辑解耦。

public interface IProduct
{void Create();
}public class ConcreteProductA : IProduct
{public void Create() => Console.WriteLine("Product A created");
}public class ConcreteProductB : IProduct
{public void Create() => Console.WriteLine("Product B created");
}public class ProductFactory
{public static IProduct GetProduct(string type){return type switch{"A" => new ConcreteProductA(),"B" => new ConcreteProductB(),_ => throw new ArgumentException("Invalid product type")};}
}

在这个示例中,工厂方法 GetProduct 负责创建 ConcreteProductA 或 ConcreteProductB,而客户端无需知道具体实现细节。

观察者模式(Observer)

观察者模式 定义了对象间的一对多依赖关系,当一个对象的状态改变时,依赖它的对象会收到通知并自动更新。这个模式常用于事件驱动的系统中。

public class Subject
{private List<IObserver> observers = new List<IObserver>();public void Attach(IObserver observer) => observers.Add(observer);public void Detach(IObserver observer) => observers.Remove(observer);public void Notify(){foreach (var observer in observers){observer.Update();}}
}public interface IObserver
{void Update();
}public class ConcreteObserver : IObserver
{public void Update() => Console.WriteLine("Observer notified");
}

在这个示例中,Subject 维护了一个观察者列表,状态改变时,Notify 方法通知所有观察者。

策略模式(Strategy)

策略模式 允许在运行时选择算法或策略,避免在代码中使用大量的条件语句。每个策略都是一个独立的类,封装了具体的算法或行为。

public interface IStrategy
{void Execute();
}public class ConcreteStrategyA : IStrategy
{public void Execute() => Console.WriteLine("Executing Strategy A");
}public class ConcreteStrategyB : IStrategy
{public void Execute() => Console.WriteLine("Executing Strategy B");
}public class Context
{private IStrategy strategy;public Context(IStrategy strategy) => this.strategy = strategy;public void ExecuteStrategy() => strategy.Execute();
}

在这个示例中,Context 类根据不同的策略执行相应的算法,策略可以在运行时动态选择。


2. SOLID 原则

SOLID 是面向对象设计的五大原则,旨在提高代码的可维护性和扩展性。这五个原则包括:

  • S:单一职责原则(Single Responsibility Principle)
    • 一个类应该只有一个职责。
  • O:开闭原则(Open/Closed Principle)
    • 软件实体应该对扩展开放,对修改关闭。
  • L:里氏替换原则(Liskov Substitution Principle)
    • 子类对象应该可以替换父类对象,并且不会导致错误。
  • I:接口隔离原则(Interface Segregation Principle)
    • 接口应该小而专,避免臃肿的接口。
  • D:依赖倒置原则(Dependency Inversion Principle)
    • 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。

这些原则确保代码设计更加清晰、灵活,并且容易扩展。例如,遵循单一职责原则可以避免一个类承担太多职责,增加了代码的可维护性;而开闭原则确保我们可以在不修改现有代码的情况下进行功能扩展。


3. 依赖注入(Dependency Injection)

依赖注入 是实现 SOLID 原则(尤其是依赖倒置原则)的重要手段。它允许我们将类的依赖项通过外部注入,而不是让类自行实例化依赖项,从而提高代码的可测试性和灵活性。

构造函数注入

public interface IService
{void Serve();
}public class Service : IService
{public void Serve() => Console.WriteLine("Service Called");
}public class Client
{private readonly IService service;public Client(IService service){this.service = service;}public void Start() => service.Serve();
}

在这个示例中,Client 类不直接依赖 Service 类,而是依赖于 IService 接口,通过构造函数将实现传递给 Client,使得 Client 更加灵活。

使用依赖注入框架

在 C# 中,通常会使用依赖注入框架(如 ASP.NET Core 的内置 DI 容器)来自动管理依赖关系。

public void ConfigureServices(IServiceCollection services)
{services.AddTransient<IService, Service>();services.AddTransient<Client>();
}

通过 DI 容器,可以自动解析依赖项并注入到构造函数中,无需手动实例化对象。这种方式极大简化了对象的管理,提升了可维护性和可测试性。


结论

设计模式和 SOLID 原则是提高代码质量、灵活性和可扩展性的有效工具。通过合理运用设计模式,我们可以解决常见的开发问题,简化系统的设计。SOLID 原则确保我们的代码结构更加清晰,避免复杂的耦合和难以维护的代码。

  • 单例模式:控制类的实例数量,适用于全局唯一对象。
  • 工厂模式:通过工厂类创建对象,解耦了对象的创建和使用。
  • 观察者模式:使得对象间的变化可以被自动通知,适用于事件驱动的场景。
  • 策略模式:允许动态选择行为或算法,避免条件判断过多的代码。
  • SOLID 原则 提高了代码设计的健壮性。
  • 依赖注入:通过外部注入依赖项,减少了类之间的耦合。

掌握这些设计模式和原则可以显著提升开发效率和代码质量。如果你有更多关于设计模式或依赖注入的疑问,欢迎继续探讨!


这篇博客为你介绍了常见的设计模式、SOLID 原则以及依赖注入的相关概念。如果你有任何问题或需要具体的实现示例,欢迎联系我!

相关文章:

掌握 C# 设计模式:从基础到依赖注入

设计模式是一种可以在开发中重复使用的解决方案&#xff0c;能够提高代码的可维护性、扩展性和复用性。C# 中常见的设计模式包括单例模式、工厂模式、观察者模式、策略模式等。本文将介绍这些常见的设计模式&#xff0c;并探讨 SOLID 原则和依赖注入&#xff08;Dependency Inj…...

根据json转HttpClient脚本

String json “{\n” " “paths”: {\n" " “/dev-api/system/subjectResult/exportUserList”: {\n" " “post”: {\n" " “tags”: [\n" " “bd-subject-result-controller”\n" " ],\n" " “summ…...

如何将LiDAR坐标系下的3D点投影到相机2D图像上

将激光雷达点云投影到相机图像上做数据层的前融合&#xff0c;或者把激光雷达坐标系下标注的物体点云的3d bbox投影到相机图像上画出来&#xff0c;都需要做点云3D点坐标到图像像素坐标的转换计算&#xff0c;也就是LiDAR 3D坐标转像素坐标。 看了网上一些文章都存在有错误或者…...

JAVA就业笔记6——第二阶段(3)

课程须知 A类知识&#xff1a;工作和面试常用&#xff0c;代码必须要手敲&#xff0c;需要掌握。 B类知识&#xff1a;面试会问道&#xff0c;工作不常用&#xff0c;代码不需要手敲&#xff0c;理解能正确表达即可。 C类知识&#xff1a;工作和面试不常用&#xff0c;代码不…...

02.04、分割链表

02.04、[中等] 分割链表 1、题目描述 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你不需要 保留 每个分区中各节点的初始相对位置。 2、解题思路 本题要求将链表分隔…...

Excel 中根据患者的就诊时间标记病例为“初诊”或“复诊”

1. 假设&#xff1a; 患者表&#xff1a;包含患者的基本信息&#xff0c;如患者 ID 和患者姓名。 病例表&#xff1a;包含病例信息&#xff0c;如患者 ID、就诊时间和就诊状态。 2. 操作步骤&#xff1a; 合并数据&#xff1a; 确保病例表中有一列包含患者 ID&#xff0c;以…...

遇到“mfc100u.dll丢失”的系统错误要怎么处理?科学修复mfc100u.dll

遇到“mfc100u.dll丢失”的系统错误会非常麻烦&#xff0c;因为mfc100u.dll是Microsoft Visual C 2010 Redistributable Package的重要部分&#xff0c;许多应用程序和游戏在运行时都需要调用这个文件。如果这个文件缺失&#xff0c;可能会导致相关软件或游戏启动失败。面对这种…...

[Linux] 逐层深入理解文件系统 (1)—— 进程操作文件

标题&#xff1a;[Linux] 文件系统 &#xff08;1&#xff09;—— 进程操作文件 个人主页水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 一、进程与打开的文件 二、文件的系统调用与库函数的关系 1.系统调用open() 三、内存中的文件描述符表 四、缓冲区…...

RT-Thread 互斥量的概念

目录 概述 1 互斥量定义 1.1 概念介绍 1.2 线程优先级翻转问题 2 互斥量管理 2.1 结构体定义 2.2 函数接口介绍 2.2.1 rt_mutex_create函数 2.2.2 rt_mutex_delete 函数 2.2.3 初始化和脱离互斥量 概述 本文主要介绍互斥量的概念&#xff0c;实现原理。还介绍RT-Thre…...

6.计算机网络_UDP

UDP的主要特点&#xff1a; 无连接&#xff0c;发送数据之前不需要建立连接。不保证可靠交付。面向报文。应用层给UDP报文后&#xff0c;UDP并不会抽象为一个一个的字节&#xff0c;而是整个报文一起发送。没有拥塞控制。网络拥堵时&#xff0c;发送端并不会降低发送速率。可以…...

Windows应急响蓝安服面试

Windows应急响应 蓝队溯源流程 学习Windows应急首先要站在攻击者的角度去学习一些权限维持和权限提升的方法.,文章中的方法其实和内网攻防笔记有类似l红队教你怎么利用 蓝队教你怎么排查 攻防一体,应急响应排查这些项目就可以 端口/服务/进程/后门文件都是为了权限维持,得到s…...

PCL 点云配准-4PCS算法(粗配准)

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 加载点云数据 2.1.2 执行4PCS粗配准 2.1.3 可视化源点云、目标点云和配准结果 2.2完整代码 三、实现效果 3.1原始点云 3.2配准后点云 PCL点云算法汇总及实战案例汇总的目录地址链接…...

12、论文阅读:利用生成对抗网络实现无监督深度图像增强

Towards Unsupervised Deep Image Enhancement With Generative Adversarial Network 摘要介绍相关工作传统图像增强基于学习的图像增强 论文中提出的方法动机和目标网络架构损失函数1) 质量损失2) 保真损失3&#xff09;身份损失4&#xff09;Total Loss 实验 摘要 提高图像的…...

Axure重要元件三——中继器表单制作

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 本节课&#xff1a;中继器表单制作 课程内容&#xff1a;利用中继器制作表单 应用场景&#xff1a;台账、表单 案例展示&#xff1a; 步骤一&#xff1a;建立一个背景区…...

DMAIC赋能智能家居:解锁未来生活新篇章!

从清晨自动拉开的窗帘&#xff0c;到夜晚自动调暗的灯光&#xff0c;每一处细节都透露着科技的温度与智慧的光芒。而在这场智能革命的浪潮中&#xff0c;DMAIC&#xff08;定义Define、测量Measure、分析Analyze、改进Improve、控制Control&#xff09;作为六西格玛管理的核心方…...

代码随想录算法训练营第二天| 209.长度最小的子数组 59.螺旋矩阵II 区间和 开发商购买土地

209. 长度最小的子数组 题目&#xff1a; 给定一个包含正整数的数组 nums 和一个正整数 target &#xff0c;找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0。 示例&#xff1a; 示例 1…...

mysql隐藏索引

1. 什么是隐藏索引&#xff1f; 在 MySQL 8 中&#xff0c;隐藏索引&#xff08;Invisible Indexes&#xff09;是指一种特殊类型的索引&#xff0c;它并不真正被删除&#xff0c;而是被标记为“不可见”。当索引被标记为不可见时&#xff0c;查询优化器在生成查询计划时将忽略…...

etcd入门到实战

概述&#xff1a;本文将介绍etcd特性、使用场景、基本原理以及Linux环境下的实战操作 入门 什么是etcd&#xff1f; etcd是一个分布式键值存储数据库 关键字解析&#xff1a; 键值存储&#xff1a;存储协议是 key—value 的形式&#xff0c;类似于redis分布式&#xff1a;…...

Build an Android project and get a `.apk` file on a Debian 11 command line

You can build an Android project and get a .apk file on a Debian 11 command line without using Android Studio. The process involves using the Android SDK command-line tools (sdkmanager, adb, and gradle). Here’s a step-by-step guide to building the ???…...

解读 Java 经典巨著《Effective Java》90条编程法则,第4条:通过私有构造器强化不可实例化的能力

文章目录 【前言】欢迎订阅【解读《Effective Java》】系列专栏java.lang.Math 类的设计经验总结 【前言】欢迎订阅【解读《Effective Java》】系列专栏 《Effective Java》是 Java 开发领域的经典著作&#xff0c;作者 Joshua Bloch 以丰富的经验和深入的知识&#xff0c;全面…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...