C#中常见的软件设计模式及应用场景

文章目录

  • 前言
  • 1、单例模式 (Singleton)
    • 1.1 详细说明
    • 1.2 应用场景示例
  • 2、工厂模式 (Factory Method)
    • 2.1 详细说明
    • 2.2 应用场景示例
  • 3、观察者模式 (Observer)
    • 3.1 详细说明
    • 3.2 应用场景示例
  • 4、策略模式 (Strategy)
    • 4.1 详细说明
    • 4.2 应用场景示例
  • 5、适配器模式 (Adapter)
    • 5.1 详细说明
    • 5.2 应用场景示例
  • 总结


前言

在C#开发中,设计模式是一种被广泛应用的软件设计思想,它可以帮助我们提高代码的可维护性、可扩展性和可复用性。本文将详细介绍C#中几种常见的软件设计模式,并提供每种模式的具体应用场景示例,以展示其在实际项目中的应用效果和益处。


1、单例模式 (Singleton)

1.1 详细说明

单例模式确保一个类只有一个实例,并提供一个全局访问点。这个模式通常用于那些只需要一个实例且频繁使用的对象,例如数据库连接池、日志对象、配置对象等。

1.2 应用场景示例

场景1: 应用程序需要一个全局的配置管理器来管理所有的配置信息。

public class ConfigurationManager
{private static ConfigurationManager _instance;private ConfigurationManager(){// 初始化配置}public static ConfigurationManager Instance{get{if (_instance == null){_instance = new ConfigurationManager();}return _instance;}}// 配置操作方法
}

场景2: 在一个多线程的环境下,需要确保某个资源只被创建一次并在全局范围内访问。比如数据库连接池的实现。

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

2、工厂模式 (Factory Method)

2.1 详细说明

工厂模式定义了一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类中进行。

2.2 应用场景示例

场景: 应用程序需要根据用户的选择创建不同类型的图形对象(如圆形、矩形)。

public interface IGraphic
{void Draw();
}public class Circle : IGraphic
{public void Draw(){Console.WriteLine("Drawing a circle");}
}public class Rectangle : IGraphic
{public void Draw(){Console.WriteLine("Drawing a rectangle");}
}public abstract class Factory
{public abstract IGraphic CreateGraphic(string type);
}public class CircleFactory : Factory
{public override IGraphic CreateGraphic(string type){return new Circle();}
}public class RectangleFactory : Factory
{public override IGraphic CreateGraphic(string type){return new Rectangle();}
}// 使用
IFactory factory = new CircleFactory();
IGraphic graphic = factory.CreateGraphic("Circle");
graphic.Draw(); // 输出: Drawing a circle

3、观察者模式 (Observer)

3.1 详细说明

观察者模式定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知并自动更新。

3.2 应用场景示例

场景1: 股票市场应用程序中,当股票价格发生变化时,需要通知所有订阅了该股票的投资者。

public interface IObserver
{void Update(float stockPrice);
}public interface ISubject
{void Attach(IObserver observer);void Detach(IObserver observer);void Notify();
}public class StockMarket : ISubject
{private List<IObserver> observers = new List<IObserver>();private float stockPrice;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(stockPrice);}}public void SetStockPrice(float price){stockPrice = price;Notify();}
}public class Investor : IObserver
{public void Update(float stockPrice){Console.WriteLine($"Stock price updated to: {stockPrice}");}
}// 使用
StockMarket stockMarket = new StockMarket();
Investor investor1 = new Investor();
Investor investor2 = new Investor();stockMarket.Attach(investor1);
stockMarket.Attach(investor2);stockMarket.SetStockPrice(100.0f); // 两个投资者都将收到通知

场景2: 在一个新闻发布订阅系统中,当有新的新闻发布时,订阅者可以自动收到通知并显示最新的新闻内容。

public interface IObserver
{void Update(string news);
}public interface ISubject
{void Attach(IObserver observer);void Detach(IObserver observer);void Notify(string news);
}public class NewsPublisher : ISubject
{private List<IObserver> observers = new List<IObserver>();private string news;public void Attach(IObserver observer){observers.Add(observer);}public void Detach(IObserver observer){observers.Remove(observer);}public void Notify(string news){this.news = news;foreach (var observer in observers){observer.Update(news);}}
}public class NewsSubscriber : IObserver
{private string name;public NewsSubscriber(string name){this.name = name;}public void Update(string news){Console.WriteLine($"{name} received news: {news}");}
}

4、策略模式 (Strategy)

4.1 详细说明

策略模式定义了一系列算法,并将每一个算法封装起来,以便它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。

4.2 应用场景示例

场景: 一个文本编辑器需要支持多种格式的文件保存方式(如纯文本、HTML、Markdown等)。

public abstract class FileSaverStrategy
{public abstract void Save(string content, string filePath);
}public class TextFileSaver : FileSaverStrategy
{public override void Save(string content, string filePath){using (StreamWriter sw = File.CreateText(filePath)){sw.Write(content);}}
}public class HtmlFileSaver : FileSaverStrategy
{public override void Save(string content, string filePath){// HTML 保存逻辑}
}public class MarkdownFileSaver : FileSaverStrategy
{public override void Save(string content, string filePath){// Markdown 保存逻辑}
}public class Document
{private FileSaverStrategy saver;public void SetSaver(FileSaverStrategy saver){this.saver = saver;}public void SaveDocument(string content, string filePath){saver.Save(content, filePath);}
}// 使用
Document document = new Document();
document.SetSaver(new TextFileSaver());
document.SaveDocument("Hello, World!", "hello.txt");//  later on, if we want to save as HTML
document.SetSaver(new HtmlFileSaver());
document.SaveDocument("<p>Hello, World!</p>", "hello.html");

5、适配器模式 (Adapter)

5.1 详细说明

适配器模式将一个类的接口转换成客户端期望的另一个接口。适配器模式让原本接口不兼容的类可以一起工作。

5.2 应用场景示例

场景: 有一个旧式的音乐播放器,只能播放MP3格式的音乐,但现在需要播放MP4格式的音乐。

public interface IMusicPlayer
{void Play(string fileExtension);
}public class Mp3MusicPlayer : IMusicPlayer
{public void Play(string fileExtension){if (fileExtension == "mp3"){Console.WriteLine("Playing MP3 music");}}
}public class Mp4MusicPlayer : IMusicPlayer
{public void Play(string fileExtension){if (fileExtension == "mp4"){Console.WriteLine("Playing MP4 music");}}
}public class Mp4ToMp3Adapter : IMusicPlayer
{private Mp4MusicPlayer mp4Player;public Mp4ToMp3Adapter(Mp4MusicPlayer mp4Player){this.mp4Player = mp4Player;}public void Play(string fileExtension){if (fileExtension == "mp3"){// 将MP4音乐转换为MP3音乐mp4Player.Play("mp4");}}
}// 使用
IMusicPlayer musicPlayer = new Mp3MusicPlayer();
musicPlayer.Play("mp3"); // 输出:Playing MP3 musicmusicPlayer = new Mp4ToMp3Adapter(new Mp4MusicPlayer());
musicPlayer.Play("mp3"); // 输出:Playing MP4 music(通过适配器转换)

总结

通过使用这些常见的设计模式,我们可以更好地组织和管理代码,提高代码的可读性、可维护性和可扩展性。每个设计模式都有其独特的应用场景和优势,在实际项目中灵活运用可以有效解决各种问题。希望本文能够帮助读者理解C#设计模式的多样性,并在实践中加以应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650014.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Relay Arm® 计算库集成

介绍 Arm 计算库&#xff08;ACL&#xff09;是一个开源项目&#xff0c;它为 Arm CPU 和 GPU 提供了加速内核。目前&#xff0c;集成将算子迁移到 ACL 以在库中使用手工制作的汇编程序例程。通过将选择算子从 Relay 计算图迁移到 ACL&#xff0c;可在此类设备上实现性能提升。…

shell编程之循环语句与函数

一 echo命令 echo -n 表示不换行输出 echo -e 表示输出转义符 常用的转义符 二 date date查看当前系统时间 -d 你描述的日期&#xff0c;显示指定字符串所描述的时间&#xff0c;而非当前时间 %F 完整日期格式&#xff0c;等价于 %Y-%m-%d % T 时间&#xff08;24小时…

构建支持 gpu 的 jupyterlab docker 镜像

构建支持 gpu 的 jupyterlab docker 镜像 1. 创建 Dockerfile2. 构建镜像3. 启动 gpu-jupyter4. 访问 gpu-jupyter 1. 创建 Dockerfile 创建一个 Dockerfile 文件&#xff0c;内容如下 FROM docker.io/nvidia/cuda:12.2.2-cudnn8-runtime-ubuntu22.04ENV DEBIAN_FRONTENDnoni…

JAVA和Go的不解之缘

JAVA和Go的不解之缘 Java和Go是两种不同的编程语言&#xff0c;它们在语法、特性和设计理念上存在一些明显的异同之处。 1. 语法和特性&#xff1a; Java是一种面向对象的语言&#xff0c;而Go则是一种面向过程的语言。Java拥有类、继承、接口等传统的面向对象特性&#xff…

Hadoop与Spark横向比较【大数据扫盲】

大数据场景下的数据库有很多种&#xff0c;每种数据库根据其数据模型、查询语言、一致性模型和分布式架构等特性&#xff0c;都有其特定的使用场景。以下是一些常见的大数据数据库&#xff1a; 1. **NoSQL 数据库**&#xff1a;这类数据库通常用于处理大规模、非结构化的数据。…

1.26学习总结

连通性判断 DFS连通性判断步骤&#xff1a; 1.从图上任意一点u开始遍历&#xff0c;标记u已经走过 2.递归u的所有符合连通条件的邻居点 3.递归结束&#xff0c;找到了的所有与u的连通点&#xff0c;就是一个连通块 4.然后重复这个步骤找到所有的连通块 BFS连通性判断步骤…

linux 查看zookeeper server运行版本号

zookeeper版本查看运行命令&#xff1a;echo stat|nc localhost 2181 显示如下图所示&#xff1a; Zookeeper version: 3.4.5-cdh6.3.2--1, built on 11/08/2019 13:15 GMT Clients: /127.0.0.1:44814[0](queued0,recved1,sent0) Latency min/avg/max: 0/0/0 Received: 9 Se…

MySQL如何避免全表扫描?

MySQL如何避免全表扫描&#xff1f; 这篇文章解释了何时以及为什么MySQL会执行全表扫描来解析查询&#xff0c;以及如何避免在大型表上进行不必要的全表扫描。 何时会发生全表扫描 MySQL使用全表扫描&#xff08;在EXPLAIN输出中的type列显示为ALL&#xff09;来解析查询的几…

防火墙的NAT

目录 1. NAT 概念解析 2. 配置NAT策略&#xff1a; 1. NAT 概念解析 静态NAT --- 一对一 动态NAT --- 多对多 NAPT --- 一对多的NAPT --- easy ip --- 多对多的NAPT 服务器映射 源NAT --- 基于源IP地址进行转换。我们之前接过的静态NAT&#xff0c;动态NAT&#xff0c;NAPT都属…

呼吸机电机控制主控MCU方案

呼吸机是一种能代替、控制或改变人的正常生理呼吸&#xff0c;增加肺通气量&#xff0c;改善呼吸功能&#xff0c;减轻呼吸功消耗&#xff0c;节约心脏储备能力的装置。呼吸机连接一条管子到患者的嘴或鼻子&#xff0c;氧气量可以通过监视器加以控制。 基于灵动微控制器的呼吸…

*【艺恩娱数】Python爬虫+数据分析可视化中国影院票房*¶

文章目录 一、记得登入才能看到所有的数据二、使用步骤艺恩数据可视化艺恩影院票房Top10艺恩影院票房销售额对比艺恩影院票房省份人次分析艺恩影院场次top10榜单 这个里面的影院名称&#xff0c;省份&#xff0c;城市&#xff0c;票房&#xff0c;场次&#xff0c;人次&#xf…

Map转成String,String 转换成Map

一、使用场景 把一个map转换成json字符串后存放在Redis中&#xff0c;然后在redis中取出json字符串&#xff0c;再把字符串转变成原来的Map 二、具体实现 1.1 Map转成String 这里使用是阿里巴巴fastjson Map<String, Object> reportData dssDashboardService.getRep…

ESXI 本地和虚拟机之间可以自由复制和粘贴

文章目录 ESXI 本地和虚拟机之间可以自由复制和粘贴 ESXI 本地和虚拟机之间可以自由复制和粘贴 web访问esxi&#xff0c;然后&#xff1a; 1、右击新建的虚拟机&#xff0c;确保是在关机状态下&#xff0c;点击编辑设置 2. 找到 虚拟机选项→高级→常规→配置参数 3、点击添加…

Unity3d C#实现三维场景中图标根据相机距离动态缩放功能

前言 如题的需求&#xff0c;其实可以通过使用UI替代场景中的图标来实现&#xff0c;不过这样UI的处理稍微麻烦&#xff0c;而且需要在图标上添加粒子特效使用SpriteRender更方便快捷。这里就根据相机离图标的位置来计算图标的缩放大小即可。这样基本保持了图标的大小&#xf…

Vulnhub靶场DC-3

本机192.168.223.128 靶机192.168.223.139 目标发现nmap -sP 192.168.223.0/24 端口扫描nmap -p- 192.168.223.139 之开启了一个80端口 看一下是什么服务 nmap -sV -p- -A 192.168.223.139是一个apache服务&#xff0c;joomla模板 看一下web 没什么有用信息。 扫描一下后台…

华为HCIP Datacom H12-831 卷18

判断题 1、对于同一个MAC地址,手工配置的MAC表项优先级高于动态的表项,某二层报文的源MAC地址已经绑定在了交换机的GEO/0/1接口,当交换机从GEO/0/2收到该报文时,会丢弃该报文 A 对 B 错 正确答案 A 解析:为了提高接口安全性,网络管理员可手工在MAC地址表中加入特定M…

银行数据仓库体系实践(3)--数据架构

狭义的数据仓库数据架构用来特指数据分布&#xff0c;广义的数据仓库数据架构还包括数据模型、数据标准和数据治理。即包含相对静态部分如元数据、业务对象数据模型、主数据、共享数据&#xff0c;也包含相对动态部分如数据流转、ETL、整合、访问应用和数据全生命周期管控治理。…

在 Vue 项目中,可以通过设置不同的环境变量来区分不同的环境,例如本地开发环境、测试环境和生产环境。以下是设置环境变量的步骤:

1、在src下新建三个文件夹 &#xff08;.env.local、.env.test 和 .env.prod&#xff09; 2、配置信息 .env.local VUE_APP_ENVlocal VUE_APP_API_URLhttp://localhost:8080.env.test VUE_APP_ENVtest VUE_APP_API_URLhttp://124.220.110.203:9090/ .env.prod VUE_APP_…

Java中实现线程的两种方式

实现线程的第一种方式&#xff1a; 编写一个类&#xff0c;直接继承java.lang.Thread,重写run方法 怎么创建线程对象&#xff1f; new就行了 怎么启动线程呢&#xff1f; 调用线程对象的start()方法 注意&#xff1a;方法体中的代码永远都是自上而下的顺序依次逐行执行。 以下…

Android源码设计模式解析与实战第2版笔记(一)

第一章 走向灵活软件之路 — 面向对象的六大原则 优化代码的第一步 — 单一职责原则 单一职责原则的英文名称是Single Responsibility Principle&#xff0c;缩写是SRP。 SRP&#xff1a;就一个类而言&#xff0c;应该仅有一个引起它变化的原因。 一个类中应该是一组相关性很…