C#配方管理系统实战:用工厂+单例模式搞定增删改查(附完整源码)

产业园区运营负责人如何实现创新资源的系统化配置?.docx 产业园区运营负责人如何实现创新资源的系统化配置? 立即下载

C#配方管理系统实战:工厂模式与单例模式的黄金组合

在工业软件和餐饮管理系统中,配方管理模块往往是核心功能之一。想象一下这样的场景:一家食品加工厂需要管理数百种产品的配方,每种配方包含原料配比、工艺参数等关键数据;或者一个连锁餐厅的中央厨房,需要确保每家分店都能准确获取最新版的标准食谱。这类系统的共同特点是需要高效、安全地处理配方的生命周期管理,同时保证全局一致性。

传统面向过程的编码方式在这里会遇到明显瓶颈——随着业务复杂度上升,代码会变得难以维护,对象创建逻辑散落在各处,状态管理混乱。这正是设计模式大显身手的时刻。本文将带你用C#实现一个工业级配方管理系统,重点演示如何将工厂模式与单例模式组合使用,解决实际开发中的三大痛点:

  1. 对象创建标准化:通过工厂模式统一配方对象的创建流程
  2. 全局访问控制:利用单例模式确保配方管理器的唯一性
  3. 业务逻辑解耦:接口设计使系统各部分保持独立演进能力

1. 系统架构设计

1.1 核心组件关系

我们先来看整体架构的UML简图(代码实现时将省略绘图相关描述)。系统主要由三个关键部分组成:

  • Recipe类:承载配方数据的实体
  • IRecipeManager接口:定义管理契约
  • RecipeManager实现类:单例模式的核心载体
  • RecipeFactory类:工厂模式的体现
// 配方实体类示例
public class Recipe
{
    public string Code { get; }  // 唯一标识符
    public string Name { get; set; }
    public Dictionary<string, decimal> Ingredients { get; } // 原料与用量
    public string ProcessFlow { get; set; } // 工艺流程说明
    
    public Recipe(string code)
    {
        Code = code;
        Ingredients = new Dictionary<string, decimal>();
    }
}

1.2 模式选择依据

为什么选择这两种模式组合?来看个对比表格:

设计模式解决的核心问题在本系统中的应用价值
工厂模式对象创建依赖统一配方创建流程,隐藏复杂初始化逻辑
单例模式全局资源访问确保全系统使用同一个配方管理器实例
组合优势-既规范了对象出生,又控制了生命周期

实际项目中,我们曾遇到多个模块各自实例化管理器导致数据不一致的问题。改用单例模式后,这类bug彻底消失。

2. 核心代码实现

2.1 单例模式的高级实现

标准的单例实现有很多种,我们选择线程安全且延迟初始化的版本:

public sealed class RecipeManager : IRecipeManager
{
    private static readonly Lazy<RecipeManager> _instance =
        new Lazy<RecipeManager>(() => new RecipeManager());
    
    private readonly ConcurrentDictionary<string, Recipe> _recipes;
    
    private RecipeManager()
    {
        _recipes = new ConcurrentDictionary<string, Recipe>();
    }
    
    public static RecipeManager Instance => _instance.Value;
    
    // 实现接口方法...
}

关键改进点:

  • 使用Lazy<T>实现真正的延迟初始化
  • 采用线程安全的ConcurrentDictionary替代普通Dictionary
  • 密封类防止派生破坏单例

2.2 工厂模式的灵活应用

基础工厂模式大家都会,但实际项目中我们需要更灵活的变体:

public static class RecipeFactory
{
    public static Recipe Create(string code, string name)
    {
        if (string.IsNullOrWhiteSpace(code))
            throw new ArgumentException("配方编码不能为空");
            
        return new Recipe(code) { Name = name };
    }
    
    public static Recipe CreateFromTemplate(string code, Recipe template)
    {
        var recipe = Create(code, template.Name);
        // 深拷贝其他属性...
        return recipe;
    }
}

工厂方法的优势在这里体现得淋漓尽致:

  • 集中校验逻辑
  • 支持多种创建方式
  • 方便后续扩展(如连接数据库获取模板)

3. 业务功能实现

3.1 增删改查的完整实现

让我们实现完整的IRecipeManager接口:

public interface IRecipeManager
{
    Recipe GetRecipe(string code);
    bool TryAddRecipe(Recipe recipe);
    bool UpdateRecipe(Recipe recipe);
    bool DeleteRecipe(string code);
    IEnumerable<Recipe> GetAllRecipes();
}

对应的实现要点:

public bool TryAddRecipe(Recipe recipe)
{
    return _recipes.TryAdd(recipe.Code, recipe);
}

public bool UpdateRecipe(Recipe recipe)
{
    return _recipes.TryUpdate(recipe.Code, recipe, _recipes.GetValueOrDefault(recipe.Code));
}

注意这里使用了原子操作来保证线程安全。实际项目中,我们还需要添加版本控制:

public class Recipe
{
    // 新增版本字段
    public int Version { get; private set; } = 1;
    
    public void IncrementVersion() => Version++;
}

3.2 典型业务场景处理

在食品行业,配方版本管理至关重要。我们扩展更新逻辑:

public bool UpdateRecipe(Recipe newVersion)
{
    if (!_recipes.TryGetValue(newVersion.Code, out var current))
        return false;
        
    if (newVersion.Version <= current.Version)
        throw new InvalidOperationException("不能回退版本");
        
    newVersion.IncrementVersion();
    return _recipes.TryUpdate(newVersion.Code, newVersion, current);
}

4. 高级应用与扩展

4.1 观察者模式集成

当配方变更时需要通知质检系统,我们可以轻松集成观察者模式:

public sealed class RecipeManager : IRecipeManager, IObservable<RecipeChangeEvent>
{
    private readonly List<IObserver<RecipeChangeEvent>> _observers = new();
    
    public IDisposable Subscribe(IObserver<RecipeChangeEvent> observer)
    {
        _observers.Add(observer);
        return new Unsubscriber(_observers, observer);
    }
    
    private void Notify(RecipeChangeEvent change)
    {
        foreach (var observer in _observers)
        {
            observer.OnNext(change);
        }
    }
    
    private class Unsubscriber : IDisposable
    {
        private readonly List<IObserver<RecipeChangeEvent>> _observers;
        private readonly IObserver<RecipeChangeEvent> _observer;
        
        public Unsubscriber(List<IObserver<RecipeChangeEvent>> observers, 
                          IObserver<RecipeChangeEvent> observer)
        {
            _observers = observers;
            _observer = observer;
        }
        
        public void Dispose()
        {
            if (_observer != null && _observers.Contains(_observer))
                _observers.Remove(_observer);
        }
    }
}

4.2 持久化存储集成

单例模式需要特别注意持久化问题。我们可以抽象存储层:

public interface IRecipeRepository
{
    Task SaveAsync(Recipe recipe);
    Task<Recipe> LoadAsync(string code);
    Task DeleteAsync(string code);
}

// 在RecipeManager中注入存储实现
private readonly IRecipeRepository _repository;

private RecipeManager(IRecipeRepository repository)
{
    _repository = repository;
    LoadInitialData();
}

5. 实战技巧与陷阱规避

5.1 单元测试策略

测试单例类需要特殊技巧:

[TestFixture]
public class RecipeManagerTests
{
    [Test]
    public void Instance_Always_ReturnsSameObject()
    {
        var instance1 = RecipeManager.Instance;
        var instance2 = RecipeManager.Instance;
        Assert.AreSame(instance1, instance2);
    }
    
    [TearDown]
    public void TearDown()
    {
        // 通过反射重置单例实例
        typeof(RecipeManager)
            .GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)
            ?.SetValue(null, null);
    }
}

5.2 常见陷阱与解决方案

陷阱现象根本原因解决方案
多线程下出现重复实例经典单例实现非线程安全使用Lazy或双重检查锁
配方更新后部分模块仍使用旧数据对象引用被缓存实现变更通知机制
单元测试相互干扰单例状态持久化测试后重置静态实例

在最近的一个制药行业项目中,我们遇到了配方变更后部分设备控制器仍使用旧配方的严重问题。最终通过实现强制的版本校验机制解决了这个问题:

public class RecipeExecutor
{
    public void Execute(Recipe recipe)
    {
        var latest = RecipeManager.Instance.GetRecipe(recipe.Code);
        if (latest.Version != recipe.Version)
            throw new StaleRecipeException(recipe.Code);
        
        // 执行逻辑...
    }
}

这套配方管理系统架构已经在多个行业项目中得到验证,从食品加工到化工生产,稳定的核心架构配合灵活的扩展点设计,能够适应各种业务场景的演进需求。当需要新增配方类型时,只需扩展工厂类;当需要添加新的管理功能时,通过接口新增方法即可,充分体现了开闭原则的价值。

西安交通大学SQ轴承数据集(文末附数据) 西安交通大学SQ轴承数据集 阅读详情

相关推荐

实战游戏项目管理1-规划篇

1、前言 做研发管理10多年,进游戏行业8年,经验下来项目管理就是一门技术,结合不同行业不同项目加以不同管理方法,但原理基本一样,这里总结下游戏项目的管理一些实操方法 一般游戏确定立项前都需要做,项目预研产出一个游戏Demo,通过公司的立项评审,这个过程的项目管理相对简单一般由制作人或其他项目经理兼任,只有控制好总体时间与成本就好,这里按立项后开始讲。 2、游戏项目规划 ...

pengdali的专栏 2万+

怎样设计一个好架构:八个评价维度、四层思考深度,以及 23 种设计模式各自解决什么问题

架构要解决的是变化、理解、故障和协作的成本。本文从耦合、可迁移、可适配、复杂度等八个维度讲怎么评价架构,讲维度之间怎么取舍、架构思考可以分几层,再用可编译的 C 代码过一遍 23 种设计模式。

weixin_52400878的博客 337

MuJoCo与Isaac Sim的无缝对接:利用USD导出功能实现强化学习场景的跨平台迁移

本文详细介绍了如何通过USD导出功能实现MuJoCo与Isaac Sim的无缝对接,助力强化学习场景的跨平台迁移。文章解析了USD格式的核心优势,包括分层合成、物理属性继承和时间轴动画,并提供了从MJCF到USD的完整转换流程及在Isaac Sim中的高级应用技巧,帮助开发者高效迁移和优化强化学习环境。

weixin_29073241的博客 518

访问者模式详解

汇总目录请点击访问:《设计模式目录汇总》 喜欢内容的话欢迎关注、点赞、收藏!感谢支持,祝大家祉猷并茂,顺遂无虞!

2601_96797912的博客 24

OpenBmc开发2:构建开发环境

编译环境VMware + ubuntu 18.04 编译环境构建:参考OpenBmc开发1:构建开发环境 1、打开一个Ternimal,进入openbmc目录下 2、查看有哪些不同的编译配置 find meta-* -name local.conf.sample 可以看到如下编译配置 3、生成编译配置 插入TEMPLATECONF,上边查询到的配置有很多,但是有一些...

master 2万+

大模型学习路线之多模态模型

​ (Frankly speaking,博主太懒了)章节一只对CLIP、BLIP、BLIP2、InstructBLIP进行了整理,章节二以CLIP、VisualGLM作为实践案例。​ 实际上多模态模型除了CLIP、BLIP、BLIP2、InstructBLIP,还有LLaVA、miniGPT4,以及国内清华的VisualGLM、阿里的Qwen-VL等。(更多多模态原理可以看文末的参考说明)一、多模态模型 & 理论。

2401_86435672的博客 2291

Agent Skill 五大设计模式:从工程实践到落地指南

Skill 不是一段临时 Prompt,而是一个可复用、可测试、可迭代的任务流程模板。通常通过SKILL.mdWhen:什么情况下触发How:按什么步骤执行What:最终输出什么:哪些行为必须遵守、哪些行为禁止fill:#333;important;important;fill:none;color:#333;color:#333;important;fill:none;fill:#333;height:1em;用户意图Skill 路由工具调用 / MCP / API结构化输出检查与交付。

m0_62458145的博客 220

手把手教你用TiggerRamDisk绕过iPhone/iPad激活锁(支持iOS16.3,Win/Mac双平台保姆级教程)

本文详细介绍了如何使用TiggerRamDisk工具绕过iPhone/iPad的激活锁,支持iOS16.3系统,并提供Windows和Mac双平台的保姆级教程。从工具准备、设备连接到核心解锁流程,一步步指导用户完成操作,帮助二手设备或旧设备重获新生。

weixin_29323493的博客 922

设计模式之状态模式

状态模式是一种行为型设计模式,通过将对象的不同状态行为封装到独立的状态类中,使上下文对象在状态变化时自动切换行为。以外卖订单为例,不同状态(如待支付、配送中)对同一操作(如取消)有不同响应。状态模式避免了复杂的if/else判断,提升代码可维护性与扩展性。其核心由上下文(Order)、状态接口(OrderState)和具体状态类组成,通过委托机制实现状态间的平滑切换。

FallingGod的博客 302

迈德威视相机调用( 基于 Linux系统+ OpenCV )

迈德威视相机调用( 基于 Linux系统+ OpenCV )前言一、登录迈德威视官网,下载官方SDK二、代码调用与视频帧处理( 基于 OpenCV )总结 前言     此博客记录了迈德威视工业相机在 Linux 系统下的代码调用及其环境配置,通过 OpenCV 对视频帧进行处理。   一、登录迈德威视官网,下载官方SDK      迈德威视官网 : http://www.mindvision.com.cn/     1. 进入官网后,在服务支持中选择软件下载。    2. 选择Linux系统S.

kkkkkk0729的博客 5680

31、车载通信中的可见光通信(VLC)技术解析

本文详细解析了车载通信中可见光通信(VLC)技术的应用背景、优势及发展前景。对比传统RF通信技术(如DSRC),VLC利用LED照明设备实现高效、安全的车辆与车辆、车辆与基础设施之间的通信,具有频谱资源丰富、安全性高、无电磁干扰等优势。文章还探讨了VLC在交叉口交通控制、高速公路通信、自动驾驶等场景的应用潜力,展望了其在未来智能交通系统中的重要作用。

hill8的博客 318

设计模式(unity游戏研发版)

当你使用图形用户界面类时通常会遇到一个问题。比如,你创建了自定义按钮类并允许客户端在按钮中注入自定义代码,这样当用户按下按钮时就会触发这些代码。观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。你可在按钮中添加订阅机制,允许客户端通过自定义订阅类注入自定义代码。在Unity中,这就像UnityEvent在Inspector中绑定多个回调。

m0_63330263的博客 107

STM32开发 -- GPS模块开发详解

一、了解硬件 我使用的GPS模块型号为UBX-M8030 参看:UBX-M8030 系列 查看一下它的特性: 多用途 GNSS 芯片,提供三种产品等级 最多可并发接收 3 个 GNSS(GPS、伽利略、GLONASS、北斗) 行业领先的 -167 dBm 导航灵敏度 业界最低电流消耗 在城市峡谷中具有绝佳的定位精度 安全性和完整性保护 支持所有的卫星增强系统 车载级芯片的工作...

不积跬步,无以至千里 3万+

设计模式之策略模式

策略模式是一种行为型设计模式,将可互换的算法封装为独立策略,使客户端可在运行时动态选择并切换算法。核心由策略接口、具体策略和上下文三部分组成。通过将算法与使用分离,实现解耦与灵活扩展。适用于多算法场景,如支付方式、排序策略等,避免冗长的if/else。

FallingGod的博客 403

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

设计模式指南 (Java 版)

设计模式是解决软件设计中常见问题的可复用方案,而非直接代码。本文以最简方式梳理三大类设计模式:创建型(如单例、工厂方法)、结构型(如适配器、装饰器)和行为型(如观察者、策略)。通过生活化类比与Java示例,强调“按需使用、避免过度设计”的原则,帮助理解其核心思想与实际应用。

sync_with_U 239

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

设计模式与生活⑬:你坐几号线,谁来运营是另一回事

一到周五,小王的心情就会好一点。倒不是工作少了,而是想到这一天忙完,后面接着双休,心里就有盼头。地铁上,他抬头看标识,发现一件平时没留意的事:5 号线、10 号线常见的是“北京地铁”,4 号线却写着“京港地铁”。再想想,北京的机场也各有各的名字:首都机场、大兴机场。可在成都坐地铁,日常看到的统一称谓就是“成都地铁”。都是出行,名称和背后的主体并不完全一样。对乘客来说,常做的事还是那几样:查线路、进站、上车、到站下车。坐几号线是一条信息,谁来运营是另一条信息,不必揉成一团。同样是在北京坐地铁,线路和运营方并不

工一木子 241

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

【第四部分:Agentic 智能体设计模式】18.Agent 并行化实战:任务拆分、并发执行与结果汇总

本文介绍 Parallelization(并行化模式)的原理与工程实现,重点分析 Fan-out / Fan-in、Sectioning、Voting、任务依赖、上下文隔离、并发控制及部分失败处理。结合采购合同并行分析案例与 Java CompletableFuture 代码,说明如何实现独立任务的并发执行、结构化结果汇总和证据校验。同时介绍 LangGraph 动态任务分发、OpenAI 并行 Subagent、LangChain 异步 Subagent 及 DeepSeek Super-agent 等近

weixin_42258782的博客 247

设计模式之访问者模式

访问者模式是一种行为型设计模式,核心思想是将操作从元素类中分离,通过“访问者”统一管理对对象结构的多种操作。适用于元素类型稳定但操作频繁变化的场景。其精髓在于双重分派:元素通过accept方法触发访问者visit,最终由元素和访问者的运行时类型共同决定具体执行逻辑。该模式避免了在元素类中添加大量方法,提升扩展性,但会增加类数量与复杂度。典型应用如编译器语法树遍历、报表统计等。

FallingGod的博客 103

设计模式与生活⑭:一栋楼,共用一份热

今天是立冬。天气预报说夜里有暴雪,白天最高也就 4 度。早上起来,屋里比外面强不了多少。窗玻璃上蒙着一层水汽,摸一把暖气片,凉的。物业群里发了通知:今天开始试供暖,暖气片会慢慢热起来,顶层记得排气,边户留意自家热不热。隔了会儿再摸,暖气片上热下凉,温温的,不烫手。再晚一点,整间屋子总算有了点热乎气。一天里最踏实的一件事,是知道这栋楼里不只自己一户在等热。热力站烧的是一锅水,顺着管网送到每家,各家只管拧自己那个阀门。试供暖第一天,暖气片温而不烫今天聊的。

工一木子 364

设计模式之模板方法模式

模板方法模式通过定义算法骨架,将可变步骤延迟至子类实现,实现流程复用。核心是父类的final模板方法锁定执行顺序,子类仅需实现抽象方法或覆盖钩子。如冲泡饮品场景中,烧水、倒杯等固定步骤由父类完成,冲泡与加调料由子类定制。该模式避免代码重复,提升扩展性,适用于流程固定但部分步骤可变的场景。

FallingGod的博客 302

LangGraph 体系实战(下):中断恢复、流式、子图与设计模式

LangGraph的动态中断机制允许用户在图执行过程中设置暂停点,等待外部输入后再继续执行,提供了人机交互接口。当中断触发时,LangGraph会通过持久化机制保存当前图状态,并无限期等待直到用户恢复执行。中断通过在任意图节点中调用 interrupt()函数实现,该函数可以接收任何可 JSON序列化的值,并将该值暴露给调用方。中断触发后,调用方根据 interrupt()暴露的信息生成反馈,重新调用图时通过 Command将反馈传递给计算图,恢复图的运行。

不吃紫菜的博客 225

工作流 vs 自主 Agent:5 种设计模式与 3 种建模方式详解

本文基于 Anthropic《Building Effective Agents》指南,系统梳理了AI应用中的两类核心架构:Workflow(编排式)与Agent(自主智能体)。强调“能画流程图就不上Agent”,提出从简单提示链到复杂自主决策的5种可组合工作流模式,并给出选型口诀与工程实践建议。核心观点:优先用确定性、可审计的Workflow,仅在任务路径未知时启用Agent,避免盲目复杂化。

分享大数据、java相关的技术 181

设计模式 - 访问者模式

概述 访问者模式(Visitor Pattern)是一种行为型设计模式,它通过为对象结构中的每个元素添加一个访问操作,使得可以在不改变元素类的前提下定义作用于这些元素的新操作。

2601_96797912的博客 192

设计模式指南 (Java 版) ㊁

本文以简洁易懂的方式介绍Java中的设计模式,按创建型、结构型、行为型分类,重点解析简单工厂与工厂方法模式。通过现实案例(如造门、招聘)类比,阐明其核心思想:封装对象创建逻辑,提升代码可维护性。强调设计模式是解决问题的指导原则,而非万能药,应避免过度设计,合理使用方能发挥最大价值。

sync_with_U 167

Day37 · 设计模式

设计模式(Design Pattern)是前人总结的、针对软件设计中反复出现问题的经典解决方案模板。它不是可以直接抄来运行的代码,而是一套"思路 + 结构"。创建型(Creational):对象怎么创建——单例、工厂方法、抽象工厂、建造者、原型;结构型(Structural):类和对象怎么组合成更大的结构——适配器、装饰器、代理、外观、桥接、组合、享元;行为型(Behavioral):对象之间怎么分工通信——策略、模板方法、观察者、迭代器、责任链、命令、状态、备忘录、访问者、中介者、解释器等。

小嘉丶学长的博客 163

设计模式概述

设计模式的意义、作用、分类等

lzy15192536135的博客 408
上一篇: Ubuntu 24.10 + ROS2 Jazzy 环境下 Velodyne VLP-16 激光雷达配置避坑指南(附IP修改技巧)
下一篇: 解密LLM生成策略:beam_search vs do_sample到底该怎么选?附HuggingFace代码示例
java5
博客等级 码龄22年 85粉丝 2103原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值