步步为营 .NET 设计模式学习笔记 二、Abstract Factory(抽象工厂)
我们以一个线程例子来说明下抽象工厂是如何工作的.平时我们都会收发邮件,那我们就做个邮件引擎线程.
定义: 抽象工厂模式是一种创建型的模式。上面的比喻说明了抽象工厂就是生产同一个系列产品的东西,因为这一系列的产品是关联的,如果混用就可能出问题,所以就统一的在抽象工厂中进行创建。当要增加一个新的产品系列时,就多写一个工厂子类并添加相应的产品子类就可以了。
我们来看一个类图。
图中,我们可以看到,客户需要得到某系列的产品的时候,直接用相应的工厂子类来创建产品就可以了。
示例用例图
接来下我们设计个邮件发送的线程实例,先看用例图:
代码设计
首先创建一个接口ISaaSProcess.cs:
/// <summary> /// 异步调用接口 /// </summary> public interface ISaaSProcess { /// <summary> /// 启动线程任务 /// </summary> void StartProcess(); /// <summary> /// 停止线程任务 /// </summary> void StopProcess(); /// <summary> /// 显示结果 /// </summary> /// <returns></returns> List< string > GetResult(); } |
然后创建一个工厂基类SaaSProcessBase.cs:
public abstract class SaaSProcessBase : ISaaSProcess { /// <summary> /// 记录Log内容 /// </summary> public List< string > _logContent = new List< string >(); public SaaSProcessBase() { } #region ISaaSProcess Members public void StartProcess() { try { InitialProcess(); if (CheckCondition()) { DoProcess(); EndProcess(); ClearProcess(); } else { _logContent.Add( "条件检测不通过,不能正常启动" ); } } catch (Exception ex) { _logContent.Add( "任务的某个线程执行过程中出现异常" + ex.Message); } } public void StopProcess() { SetLastUpdateTime(DateTime.Now); } public List< string > GetResult() { return _logContent; } /// <summary> /// 记录最后操作时间 /// </summary> /// <param name="time"></param> public void SetLastUpdateTime(DateTime time) { _logContent.Add( "线程结束时间是" + time.ToString()); } #endregion #region abstract method /// <summary> /// 检查条件是否符合 /// </summary> /// <returns></returns> public abstract bool CheckCondition(); /// <summary> /// 初始化线程 /// </summary> public abstract void InitialProcess(); /// <summary> /// 执行线程任务 /// </summary> public abstract void DoProcess(); /// <summary> /// 结束线程任务 /// </summary> public abstract void EndProcess(); /// <summary> /// 清理线程 /// </summary> public abstract void ClearProcess(); #endregion } |
然后创建一个发送邮件的工厂EmailEngine.cs:
public class EmailEngine : SaaSProcessBase { public override bool CheckCondition() { return true ; } public override void InitialProcess() { _logContent.Add( "所有数据准备完毕" ); } public override void DoProcess() { _logContent.Add( "邮件发送成功" ); } public override void EndProcess() { _logContent.Add( "邮件发送结束" ); } public override void ClearProcess() { _logContent.Add( "邮件数据清理完毕" ); } public EmailEngine() { } } |
然后再调用它:
public partial class Run : Form { public Run() { InitializeComponent(); } private void btnRun_Click( object sender, EventArgs e) { ISaaSProcess process = new EmailEngine(); process.StartProcess(); process.StopProcess(); foreach ( string result in process.GetResult()) { rtbResult.AppendText(result + "\n" ); } } } |
运行的结果如下图:
工厂子类不一定需要实现父类的所有方法,但要使子类有用的话,我们必须使它的所有方法宣布具体化。这里,就引出几种做法:1、工厂父类可以就是一个接口,以确保其 子类一定是具体的;2、我们可以继承抽象的父类,但不完全具体化,这样可以继续细分工厂子类;3、抽象的父类中含有具体的方法,这些方法也可以不加virtual修饰符。最后的这种方法可能是比较灵活一点的。
抽象工厂主要是用在需要一系列相关联的类协同工作的地方,而且这些系列的数量可能会变多,每一个系列完成的工作都不一样,但是调用接口却是一样的。另外,抽象工厂不适合这样一种情况,即每个系列内部的元素数量不能够确定,也就是说,当初设计的时候,系列中有3个配件,后面又涨成5个,之后又涨到7个,这样的话,要改动的地方将多到让人受不了。
欢迎拍砖.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架