C#中常见的设计模式
文章目录
- 引言
- 设计模式的分类
- 创建型模式 (Creational Patterns)
- 1. 单例模式 (Singleton)
- 2. 工厂方法模式 (Factory Method)
- 3. 抽象工厂模式 (Abstract Factory)
- 4. 建造者模式 (Builder)
- 结构型模式 (Structural Patterns)
- 5. 适配器模式 (Adapter)
- 6. 装饰器模式 (Decorator)
- 7. 外观模式 (Facade)
- 8. 代理模式 (Proxy)
- 行为型模式 (Behavioral Patterns)
- 9. 观察者模式 (Observer)
- 10. 策略模式 (Strategy)
- 11. 命令模式 (Command)
- 12. 模板方法模式 (Template Method)
- 总结与参考资源
- 设计模式的选择与应用
- C# 设计模式的实践建议
- 拓展学习资源
引言
设计模式(Design Pattern)代表了软件开发中针对特定问题、经过反复验证的最佳实践解决方案。它们不是可以直接转换成代码的成品,而是描述了在各种不同情况下解决问题的模板或蓝图。在 C# 开发中,熟练运用设计模式可以显著提高代码的可读性、可维护性、可扩展性和可重用性,从而构建出更健壮、更灵活的应用程序。
本文将深入探讨在 C# 开发中最常见和最实用的几类设计模式,包括创建型、结构型和行为型模式,并通过具体的 C# 代码示例和图示来阐释它们的核心思想和应用场景。
设计模式的分类
设计模式通常根据其目的或意图分为三大类:
- 创建型模式 (Creational Patterns):关注对象的创建机制,旨在以适合特定情况的方式创建对象。它们将对象的创建过程与其表示分离,使得系统独立于对象的创建、组合和表示方式。
- 结构型模式 (Structural Patterns):关注类和对象的组合,用于形成更大的结构。它们描述了如何将类或对象组合在一起以获得新的功能。
- 行为型模式 (Behavioral Patterns):关注对象之间的通信和职责分配。它们描述了对象之间如何交互以及如何分配职责,使得对象间的协作更加灵活、高效。
创建型模式 (Creational Patterns)
创建型模式提供了各种对象创建机制,从而增加了代码的灵活性和可重用性。
1. 单例模式 (Singleton)
意图:确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
场景:当系统中某个类只需要一个实例时,例如全局配置管理器、日志记录器、数据库连接池等。
C# 示例 (线程安全):
using System;public sealed class Singleton
{// 使用静态只读字段和静态构造函数确保线程安全且延迟初始化 (Lazy Initialization)private static readonly Singleton instance = new Singleton();private static readonly object padlock = new object(); // 用于旧式双重检查锁定的锁对象,但在现代.NET中通常不需要// 私有构造函数,防止外部通过 new 创建实例private Singleton(){// 初始化代码,例如加载配置等Console.WriteLine("Singleton instance created.");}// 公共静态属性,提供全局访问点public static Singleton Instance{get{// 在现代.NET中,静态字段的初始化是线程安全的,// 所以通常不需要下面的双重检查锁定代码。// 但为了演示旧式实现,保留如下:/*if (instance == null){lock (padlock){if (instance == null){instance = new Singleton();}}}*/return instance;}}// 示例方法public void LogMessage(string message){Console.WriteLine($"Logging message: {message}");}// 防止克隆 (可选,取决于具体需求)private Singleton(Singleton other) { }public object Clone() => throw new NotSupportedException("Singleton cannot be cloned.");
}// 客户端代码
public class SingletonClient
{public static void Main(string[] args){Singleton s1 = Singleton.Instance;Singleton s2 = Singleton.Instance;s1.LogMessage("First message");s2.LogMessage("Second message");if (ReferenceEquals(s1, s2)){Console.WriteLine("s1 and s2 refer to the same instance."); // 输出此行}else{Console.WriteLine("s1 and s2 refer to different instances.");}}
}
类图 (Mermaid):
注意:现代 C# 中实现线程安全的单例模式通常推荐使用 Lazy<T>
或仅依赖静态字段的线程安全初始化特性,上述代码中的双重检查锁定部分更多是为了历史演示。
2. 工厂方法模式 (Factory Method)
意图:定义一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
场景:当一个类不知道它所必须创建的对象的类时;当一个类希望由它的子类来指定它所创建的对象时;当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
C# 示例:
using System;// 产品接口
public interface IProduct
{void Operate();
}// 具体产品 A
public class ConcreteProductA : IProduct
{public void Operate(){Console.WriteLine("Operating ConcreteProductA");}
}// 具体产品 B
public class ConcreteProductB : IProduct
{public void Operate(){Console.WriteLine("Operating ConcreteProductB");}
}// 创建者 (工厂) 抽象类
public abstract class Creator
{// 工厂方法,由子类实现public abstract IProduct FactoryMethod();// 创建者也可以包含一些核心业务逻辑,这些逻辑依赖于产品对象public void SomeOperation(){// 调用工厂方法创建产品对象IProduct product = FactoryMethod();// 使用产品Console.WriteLine("Creator: The same creator's code has just worked with:");product.Operate();}
}// 具体创建者 A,负责创建 ConcreteProductA
public class ConcreteCreatorA : Creator
{public override IProduct FactoryMethod(){return new ConcreteProductA();}
}// 具体创建者 B,负责创建 ConcreteProductB
public class ConcreteCreatorB : Creator
{public override IProduct FactoryMethod(){return new ConcreteProductB();}
}// 客户端代码
public class FactoryMethodClient
{public static void Main(string[] args){Console.WriteLine("App: Launched with the ConcreteCreatorA.");ClientCode(new ConcreteCreatorA());Console.WriteLine("");Console.WriteLine("App: Launched with the ConcreteCreatorB.");ClientCode(new ConcreteCreatorB());}// 客户端代码与抽象创建者合作public static void ClientCode(Creator creator){// ...creator.SomeOperation();// ...}
}
类图 (Mermaid):
3. 抽象工厂模式 (Abstract Factory)
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
场景:当一个系统要独立于它的产品的创建、组合和表示时;当一个系统要由多个产品系列中的一个来配置时;当你要强调一系列相关的产品对象的设计以便进行联合使用时;当你提供一个产品类库,而只想显示它们的接口而不是实现时。
C# 示例:
using System;// 抽象产品 A
public interface IAbstractProductA
{string UsefulFunctionA();
}// 具体产品 A1
public class ConcreteProductA1 : IAbstractProductA
{public string UsefulFunctionA() => "The result of the product A1.";
}// 具体产品 A2
public class ConcreteProductA2 : IAbstractProductA
{public string UsefulFunctionA() => "The result of the product A2.";
}// 抽象产品 B
public interface IAbstractProductB
{string UsefulFunctionB();// 产品 B 还可以与产品 A 协作...string AnotherUsefulFunctionB(IAbstractProductA collaborator);
}// 具体产品 B1
public class ConcreteProductB1 : IAbstractProductB
{public string UsefulFunctionB() => "The result of the product B1.";public string AnotherUsefulFunctionB(IAbstractProductA collaborator){var result = collaborator.UsefulFunctionA();return $"The result of the B1 collaborating with the ({result})";}
}// 具体产品 B2
public class ConcreteProductB2 : IAbstractProductB
{public string UsefulFunctionB() => "The result of the product B2.";public string AnotherUsefulFunctionB(IAbstractProductA collaborator){var result = collaborator.UsefulFunctionA();return $"The result of the B2 collaborating with the ({result})";}
}// 抽象工厂接口
public interface IAbstractFactory
{IAbstractProductA CreateProductA();IAbstractProductB CreateProductB();
}// 具体工厂 1,创建产品 A1 和 B1
public class ConcreteFactory1 : IAbstractFactory
{public IAbstractProductA CreateProductA() => new ConcreteProductA1();public IAbstractProductB CreateProductB() => new ConcreteProductB1();
}// 具体工厂 2,创建产品 A2 和 B2
public class ConcreteFactory2 : IAbstractFactory
{public IAbstractProductA CreateProductA() => new ConcreteProductA2();public IAbstractProductB CreateProductB() => new ConcreteProductB2();
}// 客户端代码
public class AbstractFactoryClient
{public static void Main(string[] args){Console.WriteLine("Client: Testing client code with the first factory type...");ClientMethod(new ConcreteFactory1());Console.WriteLine();Console.WriteLine("Client: Testing the same client code with the second factory type...");ClientMethod(new ConcreteFactory2());}public static void ClientMethod(IAbstractFactory factory){var productA = factory.CreateProductA();var productB = factory.CreateProductB();Console.WriteLine(productB.UsefulFunctionB());Console.WriteLine(productB.AnotherUsefulFunctionB(productA));}
}
类图 (Mermaid):
4. 建造者模式 (Builder)
意图:将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
场景:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时;当构造过程必须允许被构造的对象有不同的表示时。
C# 示例:
using System;
using System.Collections.Generic;// 产品类 (例如:一份复杂的报告)
public class Report
{private List<string> parts = new List<string>();public void AddPart(string part){parts.Add(part);}public void Show(){Console.WriteLine("\nReport Parts-------");foreach (string part in parts)Console.WriteLine(part);}
}// 建造者接口
public interface IReportBuilder
{void BuildHeader();void BuildContent();void BuildFooter();Report GetReport();
}// 具体建造者:PDF 报告
public class PdfReportBuilder : IReportBuilder
{private Report report = new Report();public void BuildHeader(){report.AddPart("PDF Header: Company Logo, Title");}public void BuildContent(){report.AddPart("PDF Content: Charts, Tables, Text Paragraphs");}public void BuildFooter(){report.AddPart("PDF Footer: Page Numbers, Confidentiality Notice");}public Report GetReport(){Report result = report;// 重置建造者以备下次使用 (可选)report = new Report();return result;}
}// 具体建造者:Web 报告
public class WebReportBuilder : IReportBuilder
{private Report report = new Report();public void BuildHeader(){report.AddPart("<header>Web Header: Navigation Bar, Search</header>");}public void BuildContent(){report.AddPart("<main>Web Content: Interactive Elements, Data Grids</main>");}public void BuildFooter(){report.AddPart("<footer>Web Footer: Copyright Info, Links</footer>");}public Report GetReport(){Report result = report;report = new Report();return result;}
}// 指挥者类 (可选,有时客户端直接调用建造者)
public class ReportDirector
{private IReportBuilder builder;public ReportDirector(IReportBuilder builder){this.builder = builder;}public void ConstructReport(){builder.BuildHeader();builder.BuildContent();builder.BuildFooter();}public void SetBuilder(IReportBuilder builder){this.builder = builder;}
}// 客户端代码
public class BuilderClient
{public static void Main(string[] args){// 使用 PDF 建造者IReportBuilder pdfBuilder = new PdfReportBuilder();ReportDirector director = new ReportDirector(pdfBuilder);Console.WriteLine("Constructing PDF report:");director.ConstructReport();Report pdfReport = pdfBuilder.GetReport(); // 从建造者获取产品pdfReport.Show();Console.WriteLine("\n------------------\n");// 使用 Web 建造者IReportBuilder webBuilder = new WebReportBuilder();director.SetBuilder(webBuilder); // 更换建造者Console.WriteLine("Constructing Web report:");director.ConstructReport();Report webReport = webBuilder.GetReport(); // 从建造者获取产品webReport.Show();// 也可以不使用指挥者,客户端直接控制构建步骤Console.WriteLine("\n------------------\n");Console.WriteLine("Constructing Custom report (Client direct control):");IReportBuilder customBuilder = new PdfReportBuilder();customBuilder.BuildHeader();// customBuilder.BuildContent(); // 可以省略某些步骤customBuilder.BuildFooter();Report customReport = customBuilder.GetReport();customReport.Show();}
}
类图 (Mermaid):
结构型模式 (Structural Patterns)
结构型模式关注如何将类和对象组合成更大的结构,同时保持结构的灵活性和效率。
5. 适配器模式 (Adapter)
意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
场景:你想使用一个已经存在的类,而它的接口不符合你的需求;你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作;你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
C# 示例:
using System;// 需要被适配的类 (Adaptee)
public class Adaptee
{public void SpecificRequest(){Console.WriteLine("Called SpecificRequest() in Adaptee");}
}// 目标接口 (Target),客户端期望的接口
public interface ITarget
{void Request();
}// 适配器类 (Adapter),实现目标接口,并包含一个 Adaptee 实例
public class Adapter : ITarget
{private readonly Adaptee adaptee;public Adapter(Adaptee adaptee){this.adaptee = adaptee;}// 实现目标接口的方法,内部调用 Adaptee 的方法public void Request(){Console.WriteLine("Adapter.Request() called - forwarding to Adaptee...");adaptee.SpecificRequest();}
}// 客户端代码
public class AdapterClient
{public static void Main(string[] args){// 创建需要被适配的对象Adaptee adapteeInstance = new Adaptee();// 创建适配器,将 Adaptee 包装起来ITarget target = new Adapter(adapteeInstance);// 客户端通过目标接口调用Console.WriteLine("Client: Calling Request() on Target interface...");target.Request();}
}
类图 (Mermaid):
这种是对象适配器模式。还有一种类适配器模式,它通过多重继承(C# 不直接支持类多重继承,但可以通过接口实现)或继承 Adaptee 并实现 ITarget 来工作,但在 C# 中对象适配器更常用。
6. 装饰器模式 (Decorator)
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
场景:在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;处理那些可以撤销的职责;当不能采用生成子类的方法进行扩充时。例如,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
C# 示例:
using System;// 组件接口 (Component)
public interface ICoffee
{string GetDescription();double GetCost();
}// 具体组件 (Concrete Component)
public class SimpleCoffee : ICoffee
{public string GetDescription() => "Simple Coffee";public double GetCost() => 5.0;
}// 装饰器抽象类 (Decorator)
public abstract class CoffeeDecorator : ICoffee
{protected ICoffee decoratedCoffee;public CoffeeDecorator(ICoffee coffee){this.decoratedCoffee = coffee;}public virtual string GetDescription() => decoratedCoffee.GetDescription();public virtual double GetCost() => decoratedCoffee.GetCost();
}// 具体装饰器 A (Concrete Decorator A): 加牛奶
public class MilkDecorator : CoffeeDecorator
{public MilkDecorator(ICoffee coffee) : base(coffee){}public override string GetDescription() => base.GetDescription() + ", with Milk";public override double GetCost() => base.GetCost() + 1.5;
}// 具体装饰器 B (Concrete Decorator B): 加糖
public class SugarDecorator : CoffeeDecorator
{public SugarDecorator(ICoffee coffee) : base(coffee){}public override string GetDescription() => base.GetDescription() + ", with Sugar";public override double GetCost() => base.GetCost() + 0.5;
}// 客户端代码
public class DecoratorClient
{public static void Main(string[] args){// 点一杯简单的咖啡ICoffee simpleCoffee = new SimpleCoffee();Console.WriteLine($"Order: {simpleCoffee.GetDescription()}, Cost: {simpleCoffee.GetCost():C}");// 给简单咖啡加牛奶ICoffee milkCoffee = new MilkDecorator(simpleCoffee);Console.WriteLine($"Order: {milkCoffee.GetDescription()}, Cost: {milkCoffee.GetCost():C}");// 再加糖ICoffee milkAndSugarCoffee = new SugarDecorator(milkCoffee);Console.WriteLine($"Order: {milkAndSugarCoffee.GetDescription()}, Cost: {milkAndSugarCoffee.GetCost():C}");// 直接点一杯加牛奶和糖的咖啡ICoffee complexCoffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));Console.WriteLine($"Order: {complexCoffee.GetDescription()}, Cost: {complexCoffee.GetCost():C}");}
}
类图 (Mermaid):
7. 外观模式 (Facade)
意图:为子系统中的一组接口提供一个一致的界面。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
场景:当你要为一个复杂子系统提供一个简单接口时;客户程序与抽象类的实现部分之间存在着很大的依赖性;当你需要构建一个层次结构的子系统时,使用外观模式定义子系统中每层的入口点。
C# 示例:
using System;// 子系统组件 A
public class SubsystemA
{public void OperationA1() => Console.WriteLine("SubsystemA: Operation A1");public void OperationA2() => Console.WriteLine("SubsystemA: Operation A2");
}// 子系统组件 B
public class SubsystemB
{public void OperationB1() => Console.WriteLine("SubsystemB: Operation B1");public void OperationB2() => Console.WriteLine("SubsystemB: Operation B2");
}// 子系统组件 C
public class SubsystemC
{public void OperationC1() => Console.WriteLine("SubsystemC: Operation C1");public void OperationC2() => Console.WriteLine("SubsystemC: Operation C2");
}// 外观类 (Facade)
public class Facade
{private SubsystemA subsystemA;private SubsystemB subsystemB;private SubsystemC subsystemC;public Facade(){subsystemA = new SubsystemA();subsystemB = new SubsystemB();subsystemC = new SubsystemC();Console.WriteLine("Facade created with subsystems.");}// 提供简化的接口方法,封装子系统的复杂交互public void SimplifiedOperation1(){Console.WriteLine("\nFacade: SimplifiedOperation1() -----");subsystemA.OperationA1();subsystemB.OperationB1();subsystemC.OperationC1();}public void SimplifiedOperation2(){Console.WriteLine("\nFacade: SimplifiedOperation2() -----");subsystemA.OperationA2();subsystemC.OperationC2();}
}// 客户端代码
public class FacadeClient
{public static void Main(string[] args){// 客户端通过外观类与子系统交互Facade facade = new Facade();// 调用简化的操作facade.SimplifiedOperation1();facade.SimplifiedOperation2();}
}
类图 (Mermaid):
8. 代理模式 (Proxy)
意图:为其他对象提供一种代理以控制对这个对象的访问。
场景:远程代理(Remote Proxy)为一个位于不同的地址空间的对象提供一个本地的代理对象;虚拟代理(Virtual Proxy)根据需要创建开销很大的对象;保护代理(Protection Proxy)控制对原始对象的访问;智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。
C# 示例 (虚拟代理):
using System;
using System.Threading;// 主题接口 (Subject)
public interface IImage
{void Display();
}// 真实主题 (Real Subject) - 加载图片可能很耗时
public class RealImage : IImage
{private string filename;public RealImage(string filename){this.filename = filename;LoadImageFromDisk();}private void LoadImageFromDisk(){Console.WriteLine($"Loading image: {filename}...");// 模拟耗时操作Thread.Sleep(2000);Console.WriteLine($"Image {filename} loaded.");}public void Display(){Console.WriteLine($"Displaying image: {filename}");}
}// 代理 (Proxy) - 控制对 RealImage 的访问
public class ImageProxy : IImage
{private RealImage realImage; // 对真实主题的引用private string filename;private bool imageLoaded = false;public ImageProxy(string filename){this.filename = filename;Console.WriteLine($"ImageProxy created for {filename}. Image not loaded yet.");}public void Display(){// 虚拟代理:仅在首次需要显示时才加载真实图片if (!imageLoaded){Console.WriteLine($"Proxy: First time display request for {filename}. Loading real image now.");realImage = new RealImage(filename); // 延迟加载imageLoaded = true;}else{Console.WriteLine($"Proxy: Display request for {filename}. Image already loaded.");}// 委托给真实主题进行显示realImage.Display();}
}// 客户端代码
public class ProxyClient
{public static void Main(string[] args){Console.WriteLine("Creating proxy for image1.jpg");IImage image1 = new ImageProxy("image1.jpg");Console.WriteLine("\n--- First display call for image1.jpg ---");image1.Display(); // 此时会加载真实图片Console.WriteLine("\n--- Second display call for image1.jpg ---");image1.Display(); // 此时直接显示,不再加载Console.WriteLine("\nCreating proxy for image2.png");IImage image2 = new ImageProxy("image2.png");Console.WriteLine("\n--- Display call for image2.png ---");image2.Display(); // 加载 image2.png}
}
类图 (Mermaid):
[待续 - 行为型模式…]
行为型模式 (Behavioral Patterns)
行为型模式关注对象之间的通信方式,以及如何分配职责和算法。这些模式使得对象间的相互作用更加灵活,同时降低了系统的耦合度。
9. 观察者模式 (Observer)
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
场景:当一个抽象模型有两个方面,其中一个方面依赖于另一个方面;当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变;当一个对象必须通知其他对象,而它又不能假定其他对象是谁。
C# 示例:
using System;
using System.Collections.Generic;// 主题接口 (Subject)
public interface ISubject
{void Attach(IObserver observer);void Detach(IObserver observer);void Notify();
}// 观察者接口
public interface IObserver
{void Update(ISubject subject);
}// 具体主题类:股票
public class Stock : ISubject
{private List<IObserver> observers = new List<IObserver>();private string symbol;private double price;public Stock(string symbol, double price){this.symbol = symbol;this.price = price;}public string Symbol => symbol;public double Price{get { return price; }set{Console.WriteLine($"\n{symbol} price changed from {price} to {value}");price = value;Notify();}}public void Attach(IObserver observer){observers.Add(observer);Console.WriteLine($"Added observer to {symbol}");}public void Detach(IObserver observer){observers.Remove(observer);Console.WriteLine($"Removed observer from {symbol}");}public void Notify(){Console.WriteLine($"Notifying observers about changes to {symbol}...");foreach (var observer in observers){observer.Update(this);}}
}// 具体观察者:投资者
public class Investor : IObserver
{private string name;public Investor(string name){this.name = name;}public void Update(ISubject subject){if (subject is Stock stock){Console.WriteLine($"Investor {name} notified of {stock.Symbol}'s price change to {stock.Price}");}}
}// 客户端代码
public class ObserverClient
{public static void Main(string[] args){// 创建股票Stock msft = new Stock("MSFT", 120.00);Stock aapl = new Stock("AAPL", 150.00);// 创建投资者Investor investor1 = new Investor("John");Investor investor2 = new Investor("Alice");Investor investor3 = new Investor("Bob");// 投资者订阅股票msft.Attach(investor1);msft.Attach(investor2);aapl.Attach(investor1);aapl.Attach(investor3);// 股票价格变化,观察者会自动收到通知msft.Price = 123.45;aapl.Price = 145.67;// 投资者取消订阅msft.Detach(investor2);// 再次变化价格msft.Price = 125.40;}
}
类图 (Mermaid):
10. 策略模式 (Strategy)
意图:定义一系列的算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。
场景:当需要使用一个算法的不同变体时;当需要隐藏复杂的、与算法相关的数据结构时;当一个类定义了多种行为,且这些行为以多个条件语句的形式出现时,可以用策略模式去掉这些条件语句。
C# 示例:
using System;// 策略接口 (Strategy)
public interface ISortStrategy
{void Sort(int[] array);string Name { get; }
}// 具体策略 A:冒泡排序
public class BubbleSortStrategy : ISortStrategy
{public string Name => "Bubble Sort";public void Sort(int[] array){Console.WriteLine("Sorting using Bubble Sort...");// 冒泡排序实现for (int i = 0; i < array.Length - 1; i++){for (int j = 0; j < array.Length - i - 1; j++){if (array[j] > array[j + 1]){// 交换元素int temp = array[j];array[j] = array[j + 1];array[j + 1] = temp;}}}}
}// 具体策略 B:快速排序
public class QuickSortStrategy : ISortStrategy
{public string Name => "Quick Sort";public void Sort(int[] array){Console.WriteLine("Sorting using Quick Sort...");QuickSort(array, 0, array.Length - 1);}private void QuickSort(int[] array, int low, int high){if (low < high){int partitionIndex = Partition(array, low, high);QuickSort(array, low, partitionIndex - 1);QuickSort(array, partitionIndex + 1, high);}}private int Partition(int[] array, int low, int high){int pivot = array[high];int i = low - 1;for (int j = low; j < high; j++){if (array[j] <= pivot){i++;// 交换元素int temp = array[i];array[i] = array[j];array[j] = temp;}}// 交换元素int temp1 = array[i + 1];array[i + 1] = array[high];array[high] = temp1;return i + 1;}
}// 上下文类 (Context)
public class SortContext
{private ISortStrategy sortStrategy;public SortContext(ISortStrategy strategy){this.sortStrategy = strategy;}public void SetStrategy(ISortStrategy strategy){this.sortStrategy = strategy;Console.WriteLine($"Strategy changed to {strategy.Name}");}public void SortData(int[] array){Console.WriteLine($"Context: Sorting array using {sortStrategy.Name}");sortStrategy.Sort(array);Console.WriteLine("Context: Array is sorted");}
}// 客户端代码
public class StrategyClient
{// 辅助方法:打印数组private static void PrintArray(int[] array){Console.WriteLine("Array: " + string.Join(", ", array));}public static void Main(string[] args){// 准备数据int[] data = { 5, 2, 9, 1, 7, 6, 3 };Console.WriteLine("Original array:");PrintArray(data);// 创建上下文,初始使用冒泡排序SortContext context = new SortContext(new BubbleSortStrategy());context.SortData(data);Console.WriteLine("Sorted array (Bubble Sort):");PrintArray(data);// 准备新数据并切换到快速排序int[] newData = { 10, 4, 8, 2, 5, 9, 1, 6, 3, 7 };Console.WriteLine("\nOriginal array (new data):");PrintArray(newData);context.SetStrategy(new QuickSortStrategy());context.SortData(newData);Console.WriteLine("Sorted array (Quick Sort):");PrintArray(newData);}
}
类图 (Mermaid):
11. 命令模式 (Command)
意图:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
场景:需要抽象出待执行的动作,将这些动作参数化;在不同的时刻指定、排列和执行请求;需要支持取消操作;需要支持修改日志功能,这样当系统崩溃时,这些修改可以被重做一遍;需要支持事务操作。
C# 示例:
using System;
using System.Collections.Generic;// 接收者类 (Receiver):电灯
public class Light
{private string location;private bool isOn;public Light(string location){this.location = location;isOn = false;}public void TurnOn(){if (!isOn){isOn = true;Console.WriteLine($"{location} light is now ON");}}public void TurnOff(){if (isOn){isOn = false;Console.WriteLine($"{location} light is now OFF");}}
}// 命令接口 (Command)
public interface ICommand
{void Execute();void Undo();
}// 具体命令:打开电灯命令
public class LightOnCommand : ICommand
{private Light light;public LightOnCommand(Light light){this.light = light;}public void Execute(){light.TurnOn();}public void Undo(){light.TurnOff();}
}// 具体命令:关闭电灯命令
public class LightOffCommand : ICommand
{private Light light;public LightOffCommand(Light light){this.light = light;}public void Execute(){light.TurnOff();}public void Undo(){light.TurnOn();}
}// 具体命令:无操作
public class NoCommand : ICommand
{public void Execute() { /* 不做任何操作 */ }public void Undo() { /* 不做任何操作 */ }
}// 调用者 (Invoker):遥控器
public class RemoteControl
{private ICommand[] onCommands;private ICommand[] offCommands;private Stack<ICommand> undoCommands;private int slots;public RemoteControl(int numberOfSlots){slots = numberOfSlots;onCommands = new ICommand[slots];offCommands = new ICommand[slots];undoCommands = new Stack<ICommand>();ICommand noCommand = new NoCommand();for (int i = 0; i < slots; i++){onCommands[i] = noCommand;offCommands[i] = noCommand;}}public void SetCommand(int slot, ICommand onCommand, ICommand offCommand){if (slot >= 0 && slot < slots){onCommands[slot] = onCommand;offCommands[slot] = offCommand;}}public void PressOnButton(int slot){if (slot >= 0 && slot < slots){onCommands[slot].Execute();undoCommands.Push(onCommands[slot]);}}public void PressOffButton(int slot){if (slot >= 0 && slot < slots){offCommands[slot].Execute();undoCommands.Push(offCommands[slot]);}}public void PressUndoButton(){if (undoCommands.Count > 0){Console.WriteLine("------ Undo Operation ------");ICommand lastCommand = undoCommands.Pop();lastCommand.Undo();}else{Console.WriteLine("------ No operations to undo ------");}}public void ShowStatus(){Console.WriteLine("\n------ Remote Control Status ------");for (int i = 0; i < slots; i++){Console.WriteLine($"[Slot {i}] ON: {onCommands[i].GetType().Name}, OFF: {offCommands[i].GetType().Name}");}Console.WriteLine($"Undo stack has {undoCommands.Count} operations.\n");}
}// 客户端代码
public class CommandClient
{public static void Main(string[] args){// 创建遥控器RemoteControl remote = new RemoteControl(3);// 创建接收者Light livingRoomLight = new Light("Living Room");Light kitchenLight = new Light("Kitchen");// 创建命令LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);// 设置命令到遥控器的插槽remote.SetCommand(0, livingRoomLightOn, livingRoomLightOff);remote.SetCommand(1, kitchenLightOn, kitchenLightOff);// 显示遥控器状态remote.ShowStatus();// 操作遥控器Console.WriteLine("------ Using Remote Control ------");remote.PressOnButton(0); // 打开客厅灯remote.PressOnButton(1); // 打开厨房灯remote.PressOffButton(0); // 关闭客厅灯remote.PressUndoButton(); // 撤销上一操作(重新打开客厅灯)remote.PressOffButton(1); // 关闭厨房灯remote.PressUndoButton(); // 撤销上一操作(重新打开厨房灯)remote.PressUndoButton(); // 撤销上一操作(再次关闭客厅灯)remote.PressUndoButton(); // 撤销上一操作(再次打开厨房灯)remote.PressUndoButton(); // 撤销上一操作(再次关闭厨房灯)// 此时撤销栈已为空remote.PressUndoButton();}
}
类图 (Mermaid):
12. 模板方法模式 (Template Method)
意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
场景:当想要定义一个算法的基本结构,而让子类提供某些具体步骤时;当多个类中包含几乎相同的算法,但有少量差异时;当希望控制子类扩展,只允许在特定点进行扩展时。
C# 示例:
using System;// 抽象类 (Abstract Class)
public abstract class DocumentProcessor
{// 模板方法,定义算法骨架public void ProcessDocument(string document){Console.WriteLine("---- Starting document processing ----");// 1. 打开文档OpenDocument(document);// 2. 分析文档内容AnalyzeContent();// 3. 处理文档内容 (子类必须实现的步骤)ProcessContent();// 4. 可选的钩子方法:验证文档if (ShouldValidate()){ValidateDocument();}// 5. 保存文档SaveDocument();Console.WriteLine("---- Document processing completed ----\n");}// 具体方法 - 所有子类共享的实现protected void OpenDocument(string document){Console.WriteLine($"Opening document: {document}");}protected void AnalyzeContent(){Console.WriteLine("Analyzing document content...");}protected void SaveDocument(){Console.WriteLine("Saving processed document...");}// 抽象方法 - 子类必须实现protected abstract void ProcessContent();// 钩子方法 - 子类可以选择性覆盖protected virtual bool ShouldValidate(){return true; // 默认行为}protected virtual void ValidateDocument(){Console.WriteLine("Performing basic document validation...");}
}// 具体类:文本文档处理器
public class TextDocumentProcessor : DocumentProcessor
{protected override void ProcessContent(){Console.WriteLine("Processing TEXT document: Spell checking, formatting text...");}// 覆盖钩子方法protected override void ValidateDocument(){Console.WriteLine("Performing TEXT specific validation: Checking grammar, paragraph structure...");}
}// 具体类:PDF文档处理器
public class PdfDocumentProcessor : DocumentProcessor
{protected override void ProcessContent(){Console.WriteLine("Processing PDF document: Extracting text layers, processing forms...");}// 覆盖钩子方法,跳过验证protected override bool ShouldValidate(){return false; // PDF不需要验证}
}// 具体类:图像文档处理器
public class ImageDocumentProcessor : DocumentProcessor
{protected override void ProcessContent(){Console.WriteLine("Processing IMAGE document: Adjusting levels, applying filters...");}// 覆盖钩子方法protected override void ValidateDocument(){Console.WriteLine("Performing IMAGE specific validation: Checking resolution, color profile...");}
}// 客户端代码
public class TemplateMethodClient
{public static void Main(string[] args){Console.WriteLine("Processing a text document:");DocumentProcessor textProcessor = new TextDocumentProcessor();textProcessor.ProcessDocument("report.txt");Console.WriteLine("Processing a PDF document:");DocumentProcessor pdfProcessor = new PdfDocumentProcessor();pdfProcessor.ProcessDocument("manual.pdf");Console.WriteLine("Processing an image document:");DocumentProcessor imageProcessor = new ImageDocumentProcessor();imageProcessor.ProcessDocument("photo.jpg");}
}
类图 (Mermaid):
总结与参考资源
设计模式的选择与应用
在实际开发中,选择合适的设计模式需要考虑以下几点:
- 问题的本质:设计模式是解决特定问题的方案,首先要明确问题的本质。
- 系统需求:考虑系统的可扩展性、可维护性、性能等需求。
- 过度设计的风险:不要为了使用设计模式而使用设计模式,避免不必要的复杂性。
- 团队经验:考虑团队成员对设计模式的熟悉程度。
C# 设计模式的实践建议
- 结合 C# 特性:利用 C# 的语言特性(如泛型、LINQ、异步编程)与设计模式结合。
- 参考现有框架:学习 .NET 框架本身如何应用设计模式(例如,ASP.NET Core 中的中间件管道使用了责任链模式)。
- 测试驱动开发:通过单元测试验证设计模式的实现是否符合预期。
- 保持简单:记住 KISS 原则(Keep It Simple, Stupid),不要过度设计。
拓展学习资源
-
在线资源:
- Microsoft Learn
- Refactoring.Guru
- SourceMaking
-
开源项目:
- .NET 运行时源码
- ASP.NET Core
通过深入理解设计模式并结合 C# 的特性灵活应用,你可以构建出更加健壮、灵活、可维护的软件系统。设计模式是工具,而不是目标——它们的价值在于解决实际问题的能力。
相关文章:
C#中常见的设计模式
文章目录 引言设计模式的分类创建型模式 (Creational Patterns)1. 单例模式 (Singleton)2. 工厂方法模式 (Factory Method)3. 抽象工厂模式 (Abstract Factory)4. 建造者模式 (Builder) 结构型模式 (Structural Patterns)5. 适配器模式 (Adapter)6. 装饰器模式 (Decorator)7. 外…...
C# 枚举(Enum)声明与使用详解
在 C# 编程中,枚举(Enum)是一种非常实用的数据类型,它允许你定义一组具有名称的整型常量,使代码更具可读性和可维护性。枚举可以有效地替代使用硬编码数值,尤其是在处理状态、选项或标志时。本文将深入探讨…...
Linux-进程控制
目录 一、进程创建 1.1、fork()函数 1.2、fork的返回值 1.3、写实拷贝(Copy-on-Write,COW) 1.4、fork常规用法 1.5、fork调用失败的原因 二、进程退出 三、进程等待 1、wait和waitpid 1.1、解决僵尸进程问题 1.2、status参数 程序正…...
【优选算法 | 滑动窗口】滑动窗口算法:高效处理子数组和子串问题
算法相关知识点可以通过点击以下链接进行学习一起加油!双指针 在本篇文章中,我们将深入剖析滑动窗口算法的核心原理。从基础概念到实战应用,带你了解如何利用滑动窗口高效解决连续子数组和子串等问题。无论你是算法入门的新手,还是…...
RabbitMQ全栈实践手册:从零搭建消息中间件到SpringAMQP高阶玩法
目录 前言 认识MQ 同步调用 异步调用 技术选型 安装 SpringAMQP 交换机类型 队列交换机绑定 环境搭建 Fanout交换机 声明队列和交换机 消息发送 消息接收 总结 Direct交换机 声明队列和交换机 消息发送 消息接收 总结 Topic交换机 声明队列和交换机 消息…...
头歌实训之存储过程、函数与触发器
🌟 各位看官好,我是maomi_9526! 🌍 种一棵树最好是十年前,其次是现在! 🚀 今天来学习C语言的相关知识。 👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更…...
系统架构设计中的DSSA方法:理论、实践与行业深度应用
引言 在软件架构设计领域,DSSA(Domain-Specific Software Architecture,领域特定软件架构)是一种专注于垂直行业或业务领域的架构设计方法论。与通用架构设计不同,DSSA通过提炼领域共性需求、构建可复用资产库&am…...
设计心得——数据结构的意义
一、数据结构 在老一些的程序员中,可能都听说过,程序其实就是数据结构算法这种说法。它是由尼克劳斯维特在其著作《算法数据结构程序》中提出的,然后在一段时期内这种说法非常流行。这里不谈论其是否正确,只是通过这种提法&#…...
【C】初阶数据结构12 -- 冒泡排序
本篇文章主要讲解经典排序算法 -- 冒泡排序。 目录 1 算法思想 2 代码 3 时间复杂度与空间复杂度分析 1) 时间复杂度 2) 空间复杂度 1 算法思想 选择排序是一种经典的交换排序算法。其算法思想也比较简单,主要是比较相邻元素&…...
HTTP, AMQP, MQTT之间的区别和联系是什么?华为云如何适配?
目录 🔗 一、共同点(联系): 🔍 二、区别对比: 📘 三、简要说明 1. HTTP 2. AMQP 3. MQTT 🔗 四、三者联系(在华为云IoT平台中的应用) 🎯 …...
WPF之项目创建
文章目录 引言先决条件创建 WPF 项目步骤理解项目结构XAML 与 C# 代码隐藏第一个 "Hello, WPF!" 示例构建和运行应用程序总结相关学习资源 引言 Windows Presentation Foundation (WPF) 是 Microsoft 用于构建具有丰富用户界面的 Windows 桌面应用程序的现代框架。它…...
CrewAI Community Version(二)——Agent
目录 1. Agent总览2. Agent属性3. 创建Agent3.1 YAML配置3.2 直接用代码定义3.3 运行结果 参考 1. Agent总览 在CrewAI框架中,Agent是一个能具备下列能力的自主单元: 1. 执行特定的任务 2. 基于它的角色和目标进行决策 3. 使用工具完成任务 …...
阿里云VS AWS中国区:ICP备案全攻略与常见误区解析
导语 在中国大陆开展互联网服务时,ICP备案是必不可少的合规步骤。然而,随着云服务的多样化,许多企业在选择备案路径时常常感到困惑。本文将深入解析阿里云和AWS中国区的备案区别,为您提供清晰的操作指南,助您避开备案陷阱,确保业务合规运营。 一、备案基本原则 1. 服务器决定…...
基于libdxfrw库读取样条曲线并离散为点
在计算机辅助设计(CAD)与制造(CAM)领域,DXF(Drawing Exchange Format)格式文件被广泛用于存储与交换矢量图形信息。样条曲线作为DXF文件中常见的复杂曲线类型,其准确读取与离散化处理…...
学习 Apache Kafka
学习 Apache Kafka 是一个很好的选择,尤其是在实时数据流处理和大数据领域。以下是一个系统化的学习建议,帮助你从入门到进阶掌握 Kafka: 1. 先决条件 在开始 Kafka 之前,确保你具备以下基础: Java 基础:K…...
5.3/Q1,GBD数据库最新文章解读
文章题目:The burden and trend prediction of ischemic heart disease associated with lead exposure: Insights from the Global Burden of Disease study 2021 DOI:10.1186/s12940-025-01155-w 中文标题:与铅暴露相关的缺血性心脏病的负担…...
java智慧城管综合管理系统源码,前端框架:vue+element;后端框架:springboot;移动端:uniapp开发,技术前沿,可扩展性强
智慧城管综合执法系统采用B/S模式设计与手机等移动终端架构,采用 java编程语言前端框架:vueelement;后端框架:springboot;数据库:mysql5.7;移动端:uniapp技术开发设计。具有使用与维…...
【锂电池剩余寿命预测】GRU门控循环单元锂电池剩余寿命预测(Matlab完整源码)
目录 效果一览程序获取程序内容代码分享研究内容GRU门控循环单元在锂电池剩余寿命预测中的应用摘要关键词1. 引言1.1 研究背景1.2 研究现状与问题1.3 研究目的与意义2. 文献综述2.1 锂电池剩余寿命预测传统方法2.2 深度学习在锂电池寿命预测中的应用2.3 研究空白与本文切入点3.…...
开发首个Spring Boot应用
📋 前置条件 🎯 在开始之前,请打开终端并运行以下命令以确保已安装正确版本的 Java: $ java -version openjdk version "17.0.4.1" 2022-08-12 LTS OpenJDK Runtime Environment (build 17.0.4.11-LTS) OpenJDK 64-Bi…...
2025第十六届蓝桥杯大赛(软件赛)网络安全赛 Writeup
2025第十六届蓝桥杯大赛(软件赛)网络安全赛 Writeup 2025第十六届蓝桥杯大赛(软件赛)网络安全赛 Writeup情报收集黑客密室逃脱 数据分析ezEvtxflowzip 密码破解EnigmaECBTraineasy_AES 逆向分析ShadowPhases 漏洞挖掘分析RuneBrea…...
HTTP 协议深度解析:从基础到实战的完整指南
HTTP(HyperText Transfer Protocol)是 应用层协议,用于客户端(浏览器、APP)与服务器之间的数据交互。以下从协议原理、核心机制到实际案例全面解析,涵盖 HTTP/1.1 到 HTTP/3 的演进。 一、HTTP 核心特性 …...
5G助力智慧城市的崛起——从概念到落地的技术实践
5G助力智慧城市的崛起——从概念到落地的技术实践 引言:智慧城市中的“隐形脉络” 随着城市化的快速推进,传统的城市管理方式已经难以满足人口增长和资源优化的需求。智慧城市的概念应运而生,通过技术创新实现智能化、可持续发展的城市生态…...
4.25test
R7-5 小黄与研究生会(20) 分数 12 全屏浏览 切换布局 作者 王秀 单位 福州大学 福州大学研究生院怡山的同学们为了在国家对抗新冠疫情期间献出自己的一份力量,他们决定为奋战在一线的医护人员送去了演出。小黄作为研究生协会的会长,他让每位男同学均带去了若干只猫或狗…...
Unity-Shader详解-其一
今天我们来介绍Unity的一大核心组件:shader。 Shader Shader就是我们的着色器,用于控制图形的渲染的计算和生成。 对于不同的引擎,具体实现渲染的方法也不一样,也就是我们俗称的不同的图形引擎API,比如OpenGL,Direct…...
WPF与C++ 动态库交互
WPF与C++动态库交互技术详解 一、基本交互方式概述 WPF应用程序与C++动态库交互主要有以下几种方式: P/Invoke调用(平台调用)COM互操作C++/CLI桥接层内存映射文件命名管道/Socket通信本文将重点介绍最常用的P/Invoke和C++/CLI两种…...
自动化测试实战篇
文章目录 目录1. 自动化实施步骤1.1 编写web测试用例1.2 自动化测试脚本开发1.3 测试报告 目录 自动化实施步骤 1. 自动化实施步骤 1.1 编写web测试用例 注: 因为这里仅作为演示,所以设计的用例并不是非常完整 1.2 自动化测试脚本开发 # common/Util…...
基于pandoc的MarkDown格式与word相互转换小工具开发(pyqt5)
这里写目录标题 开发目标准备工作源代码程序打包其他事项命令行使用pandoc关于pandoc默认表格无边框的说明 开发目标 采用word格式模板,实现高级定制样式。具备配置保存功能,方便快捷。自定义转换选项、pandoc路径。 准备工作 开发环境:Wi…...
JVM知识点(一)---内存管理
一、JVM概念 什么是JVM? 定义: Java Virtual Machine - java程序的运行环境(java二进制字节码的运行环境) 好处: 一次编写,到处运行自动内存管理,垃圾回收功能数组下标越界越界检查多态 比较jvm jre jdk区别 学习路…...
Apache NetBeans 25 发布
Apache NetBeans 25 已于 2025 年 2 月 20 日发布3。NetBeans 是一个主要面向 Java 的集成开发环境,同时支持 C/C、PHP、JavaScript 和其他编程语言1。以下是一些主要的更新内容: Gradle 的优化与增强:优化单文件测试功能,即使测试…...
【设计模式区别】装饰器模式和适配器模式区别
装饰器模式(Decorator Pattern)和适配器模式(Adapter Pattern)都是 结构型设计模式 或者说 包装模式 (Wrapper),用于解决对象的组合和扩展问题,但它们的核心目的、结构和使用场景有显…...
矫平机终极指南:特殊材料处理、工艺链协同与全球供应链管理
一、特殊材料矫平:挑战与创新解决方案 1. 高温合金(如Inconel 718)处理 技术难点: 屈服强度高达1100 MPa,传统矫平力不足 高温下易氧化,需惰性气体保护环境 解决方案: 采用双伺服电机驱动&a…...
stm32进入睡眠模式的几个注意点
(1)关闭systick (2)先关闭外设时钟,再屏蔽中断,避免先屏蔽中断再关闭外设时钟导致中断挂起无法进入睡眠模式(立即被唤醒)。 参考: 注:图片截自《RM0433参考手…...
深入理解网络安全中的加密技术
1 引言 在当今数字化的世界中,网络安全已经成为个人隐私保护、企业数据安全乃至国家安全的重要组成部分。随着网络攻击的复杂性和频率不断增加,保护敏感信息不被未授权访问变得尤为关键。加密技术作为保障信息安全的核心手段,通过将信息转换为…...
学习设计模式《六》——抽象工厂方法模式
一、基础概念 抽象工厂模式的本质是【选择产品簇(系列)的实现】; 抽象工厂模式定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类; 抽象工厂模式功能:抽象工厂的功能是为一系列相关对象或相互依…...
MySQL 数据类型
文章目录 数据类型数据类型分类数据类型tinyint类型(整型)总结bit类型(字节) 浮点类型float类型decimal类型 字符串类型char类型varchar(变长字符串) char 和 varchar的对比日期类型enum和set类型ÿ…...
基于Tcp协议的应用层协议定制
前言:本文默认读者已掌握 TCP 协议相关网络接口知识,将聚焦于应用层协议的设计与剖析,有关底层通信机制及业务逻辑部分仅作简要概述,不再展开详述。 目录 服务器 一、通信 二、协议 1.序列化与反序列化 2. 封包与解包 三、业…...
Flink反压问题解析
一、什么是反压(Backpressure)? 反压(Backpressure) 是流处理系统中的一种流量控制机制。当下游算子处理速度低于上游数据生产速度时,系统会向上游传递压力信号,迫使上游降低数据发送速率,避免数据堆积和系统崩溃。 Flink 通过动态反压机制实现这一过程,但其副作用是…...
C语言中结构体的字节对齐的应用
一、字节对齐的基本原理 计算机的内存访问通常以固定大小的块(如 4 字节、8 字节)为单位。若数据的内存地址是块大小的整数倍,称为 自然对齐。例如: int(4 字节)的地址应为 4 的倍数。 double(…...
大规模数据同步后数据总条数对不上的系统性解决方案:从字段映射到全链路一致性保障
一、引言 在数据同步(如系统重构、分库分表、多源整合)场景中,“本地数据一致,生产环境条数对不上”是典型痛点。问题常源于并发处理失控、数据库性能瓶颈、字段映射错误、缓存脏数据等多维度缺陷。本文结合实战经验,…...
美团Java后端二面面经!
场景题是面试的大头,建议好好准备 Q. [美团]如何设计一个外卖订单的并发扣减库存系统? Q.[美团]为啥初始标记和重新标记需要STW? Q.[美团]骑手位置实时更新,如何保证高并发写入? Q.[美团]订单表数据量过大导致查询…...
35-疫苗预约管理系统(微服务)
技术: RuoYi框架 后端: SpringBootMySQLspringCloudnacosRedis 前端: vue3 环境: Idea mysql maven jdk1.8 用户端功能 1.首页:展示疫苗接种须知标语、快速预约模块 2.疫苗列表:展示可接种的疫苗 3.预约接种: 用户可进行疫苗预约接种 修改预约时间 …...
Ext JS模拟后端数据之SimManager
Ext.ux.ajax.SimManager 是 Ext JS 框架中用于拦截 Ajax 请求并返回模拟数据的核心工具,适用于前后端分离开发、原型验证或独立测试场景。它通过配置灵活的规则和模拟处理器(Simlet),帮助开发者在不依赖真实后端的情况下完成前端功能开发。 simlets 是simulated servers的…...
BT169-ASEMI无人机专用功率器件BT169
编辑:ll BT169-ASEMI无人机专用功率器件BT169 型号:BT169 品牌:ASEMI 封装:SOT-23 批号:最新 引脚数量:3 特性:单向可控硅 工作温度:-40℃~150℃ BT169单向可控硅ÿ…...
4月26日星期六今日早报简报微语报早读
4月26日星期六,农历三月廿九,早报#微语早读。 1、广州多条BRT相关线路将停运,全市BRT客运量较高峰时大幅下降; 2、国务院批复:同意在海南全岛等15地设立跨境电商综合试验区; 3、我国首次实现地月距离尺度…...
如何将 sNp 文件导入并绘制到 AEDT (HFSS)
导入 sNp 文件 打开您的项目,右键单击 “Result” 绘制结果 导入后,用户可以选择它进行打印。请参阅下面的示例。要点:确保从 Solution 中选择它。...
Shell脚本-for循环应用案例
在Shell脚本编程中,for循环是一种强大的工具,用于处理重复性任务。无论是批量处理文件、遍历目录内容还是简单的计数任务,for循环都能提供简洁而有效的解决方案。本文将通过几个实际的应用案例来展示如何使用for循环解决具体的编程问题。 案…...
MATLAB基础应用精讲-【基础知识篇】发布和共享 MATLAB 代码
目录 MATLAB发布代码---生成文档pdf 分节符对发布文件的分节 实时脚本 Matlab workspace与m脚本数据共享 发布和共享 MATLAB 代码 在实时编辑器中创建和共享实时脚本 发布 MATLAB 代码文件 (.m) 添加帮助和创建文档 发布 MATLAB 代码文件 (.m) 可创建包括您的代码、注释…...
Shell脚本-while循环语法结构
在Shell脚本编程中,while循环是一种重要的流程控制语句,它允许我们重复执行一段代码,直到指定的条件不再满足为止。与for循环不同,while循环通常用于条件驱动的迭代,而不是基于列表或范围的迭代。本文将详细介绍Shell脚…...
Java基础第四章、面向对象
一、成员变量 示例: 二、JVM内存模型 类变量就是静态变量 三、构造方法 默认构造方法、定义的构造方法(不含参数、含参数) 构造方法重载: this关键字 this关键字应用:对构造方法进行复用,必须放在第一行 四、面向对象的三大特征 1…...
【基础IO上】复习C语言文件接口 | 学习系统文件接口 | 认识文件描述符 | Linux系统下,一切皆文件 | 重定向原理
1.关于文件的预备知识 1.1 文件的宏观理解 广义上理解,键盘、显示器等都是文件,因为我们说过“Linux下,一切皆文件”,当然我们现在对于这句话的理解是片面的;狭义上理解,文件在磁盘上,磁盘是一…...