C#的简单工厂模式、工厂方法模式、抽象工厂模式
工厂模式是一种创建型设计模式,主要将对象的创建和使用分离,使得系统更加灵活和可维护。常见的工厂模式有简单工厂模式、工厂方法模式和抽象工厂模式,以下是 C# 实现的三个案例:
简单工厂模式
简单工厂模式通过一个工厂类来创建对象,而不需要把客户端代码与具体类的实现细节绑定在一起。
using System;// 1. 定义产品接口
public interface IProduct
{void Use();
}// 2. 创建具体产品类
public class ConcreteProductA : IProduct
{public void Use(){Console.WriteLine("using ConcreteProductA");}
}public class ConcreteProductB : IProduct
{public void Use(){Console.WriteLine("using ConcreteProductB");}
}// 3. 创建工厂类
public class ProductFactory
{public static IProduct CreateProduct(string type){switch (type){case "a":return new ConcreteProductA();case "b":return new ConcreteProductB();default:throw new ArgumentException("unknown product type");}}
}// 4. 运用业务代码
class Program
{static void Main(string[] args){IProduct productA = ProductFactory.CreateProduct("a");productA.Use();IProduct productB = ProductFactory.CreateProduct("b");productB.Use();}
}
代码解析:
- 定义了一个
IProduct接口,其中包含Use方法,这是所有具体产品类需要实现的功能。 ConcreteProductA和ConcreteProductB是具体的产品类,它们实现了IProduct接口,分别实现了自己的Use方法。ProductFactory是工厂类,它的静态方法CreateProduct根据传入的参数(这里是字符串)来决定创建并返回哪个具体产品类的实例。- 在
Main方法中,应用业务代码通过调用ProductFactory.CreateProduct方法来获取产品实例,而不需要关心具体的创建过程,降低了客户端与具体产品类的耦合度。
工厂方法模式
工厂方法模式将对象的创建放在一个接口中,但让子类决定实例化哪一个类,使一个类的实例化延迟到其子类。
using System;// 1. 定义产品接口
public interface IProduct
{void Use();
}// 2. 创建具体产品类
public class ConcreteProductA : IProduct
{public void Use(){Console.WriteLine("using ConcreteProductA");}
}public class ConcreteProductB : IProduct
{public void Use(){Console.WriteLine("using ConcreteProductB");}
}// 3. 定义抽象工厂类
public abstract class ProductFactory
{public abstract IProduct CreateProduct();
}// 4. 创建具体工厂类
public class ConcreteProductAFactory : ProductFactory
{public override IProduct CreateProduct(){return new ConcreteProductA();}
}public class ConcreteProductBFactory : ProductFactory
{public override IProduct CreateProduct(){return new ConcreteProductB();}
}// 5. 运用业务代码
class Program
{static void Main(string[] args){ProductFactory factoryA = new ConcreteProductAFactory();IProduct productA = factoryA.CreateProduct();productA.Use();ProductFactory factoryB = new ConcreteProductBFactory();IProduct productB = factoryB.CreateProduct();productB.Use();}
}
代码解析:
- 同样先定义了
IProduct接口和两个具体的产品类ConcreteProductA、ConcreteProductB。 - 新增了一个抽象工厂类
ProductFactory,其中包含一个抽象方法CreateProduct,用于创建产品实例。 ConcreteProductAFactory和ConcreteProductBFactory是具体的工厂类,它们继承自ProductFactory并实现了CreateProduct方法,分别负责创建ConcreteProductA和ConcreteProductB的实例。- 在应用业务代码中,通过创建不同的具体工厂类实例,调用其
CreateProduct方法来获取对应的产品实例。这种方式符合开闭原则,当需要增加新的产品时,只需要新增对应的产品类和工厂类,而无需修改现有的工厂类代码。
抽象工厂模式
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
using System;// 1. 定义抽象产品接口1
public interface ICar
{void Drive();
}// 2. 定义抽象产品接口2
public interface IMotorcycle
{void Ride();
}// 3. 创建具体产品类 - 汽车
public class HondaCar : ICar
{public void Drive(){Console.WriteLine("Driving Honda Car");}
}public class ToyotaCar : ICar
{public void Drive(){Console.WriteLine("Driving Toyota Car");}
}// 4. 创建具体产品类 - 摩托车
public class HondaMotorcycle : IMotorcycle
{public void Ride(){Console.WriteLine("Riding Honda Motorcycle");}
}public class ToyotaMotorcycle : IMotorcycle
{public void Ride(){Console.WriteLine("Riding Toyota Motorcycle");}
}// 5. 定义抽象工厂接口
public interface IAutoFactory
{ICar CreateCar();IMotorcycle CreateMotorcycle();
}// 6. 创建具体工厂类
public class HondaFactory : IAutoFactory
{public ICar CreateCar(){return new HondaCar();}public IMotorcycle CreateMotorcycle(){return new HondaMotorcycle();}
}public class ToyotaFactory : IAutoFactory
{public ICar CreateCar(){return new ToyotaCar();}public IMotorcycle CreateMotorcycle(){return new ToyotaMotorcycle();}
}// 7. 应用业务代码
class Program
{static void Main(string[] args){IAutoFactory hondaFactory = new HondaFactory();ICar hondaCar = hondaFactory.CreateCar();IMotorcycle hondaMotorcycle = hondaFactory.CreateMotorcycle();hondaCar.Drive();hondaMotorcycle.Ride();IAutoFactory toyotaFactory = new ToyotaFactory();ICar toyotaCar = toyotaFactory.CreateCar();IMotorcycle toyotaMotorcycle = toyotaFactory.CreateMotorcycle();toyotaCar.Drive();toyotaMotorcycle.Ride();}
}
代码解析:
- 定义了两个抽象产品接口
ICar和IMotorcycle,分别表示汽车和摩托车产品的行为。 - 创建了多个具体产品类,如
HondaCar、ToyotaCar、HondaMotorcycle、ToyotaMotorcycle,它们分别实现对应的抽象产品接口。 - 抽象工厂接口
IAutoFactory声明了两个创建产品的方法CreateCar和CreateMotorcycle,用于创建汽车和摩托车。 HondaFactory和ToyotaFactory是具体的工厂类,实现了IAutoFactory接口,负责创建对应品牌的汽车和摩托车实例。- 在应用业务代码中,通过选择不同的具体工厂类,可以创建出不同品牌的汽车和摩托车产品,并且这些产品之间是相关联的,比如都是同一品牌下的不同类型交通工具。 当需要增加新的品牌或产品类型时,需要修改抽象工厂接口和所有具体工厂类,这是抽象工厂模式的一个缺点,但它可以确保创建出来的一系列产品的一致性。
简单工厂模式
- 优点:
- 实现简单:模式结构简单,易于理解和实现,适合初学者快速上手和小型项目开发。
- 解耦对象创建和使用:将对象创建逻辑封装在工厂类中,客户端无需了解具体创建过程,只需与工厂类交互获取对象,降低了客户端与具体产品类的耦合度。
- 便于代码维护:当创建对象的逻辑发生变化时,只需修改工厂类,而无需改动客户端代码,在一定程度上方便了维护。
- 缺点:
- 违背开闭原则:当需要增加新的产品类型时,必须修改工厂类的代码来添加新的创建逻辑,这可能会引入新的错误,并且违反了软件设计中对扩展开放、对修改关闭的开闭原则。
- 工厂类职责过重:随着产品种类不断增加,工厂类中的条件判断逻辑会变得越来越复杂,导致工厂类难以维护和理解,不符合单一职责原则。
- 应用场景:
- 产品种类较少且稳定:当项目中需要创建的对象种类较少,且后期很少会有新增产品类型的情况时,简单工厂模式可以很好地简化对象的创建过程。
- 需求变化不大:如果业务需求相对稳定,对软件的扩展性要求不高,使用简单工厂模式可以快速实现对象的创建管理。
工厂方法模式
- 优点:
- 符合开闭原则:新增产品时,只需创建新的具体产品类和对应的具体工厂类,无需修改现有代码,提高了系统的扩展性和可维护性。
- 责任明确:每个具体工厂类只负责创建一种具体产品,符合单一职责原则,使得代码结构更加清晰,便于理解和维护。
- 解耦程度高:客户端只与抽象工厂类和抽象产品类交互,具体产品的创建过程被完全封装在具体工厂类中,进一步降低了客户端与具体产品的耦合度。
- 缺点:
- 类数量增多:每增加一种产品,就需要增加一个具体产品类和一个具体工厂类,导致系统中的类数量快速增加,增加了代码的复杂性和管理成本。
- 理解难度增加:由于引入了抽象工厂类和多个具体工厂类,相比简单工厂模式,工厂方法模式的结构更加复杂,需要开发者花费更多时间来理解和掌握。
- 应用场景:
- 产品不断扩展:适用于产品种类会不断增加和变化的场景,例如电商系统中商品类型的不断扩充。
- 创建逻辑多样化:当不同产品的创建逻辑差异较大时,工厂方法模式可以将不同的创建逻辑分别封装在各自的具体工厂类中,使代码更加清晰。
抽象工厂模式
- 优点:
- 高度解耦:客户端通过抽象工厂接口获取产品,与具体产品类和具体工厂类的实现细节完全解耦,提高了系统的独立性和可维护性。
- 方便维护产品族:可以轻松地创建一系列相关或相互依赖的产品对象,即产品族,保证了产品族中各个产品之间的一致性和完整性,便于对产品族进行统一管理和维护。
- 易于切换产品族:在运行时可以很方便地切换不同的具体工厂,从而获取不同产品族的对象,增强了系统的灵活性和可扩展性。
- 缺点:
- 结构复杂:抽象工厂模式涉及多个抽象产品类、具体产品类、抽象工厂类和具体工厂类,结构较为复杂,增加了系统的理解和实现难度。
- 维护成本高:当产品族中需要增加新的产品时,不仅需要修改抽象工厂接口,还需要修改所有具体工厂类,维护成本较高,违背了开闭原则。
- 应用场景:
- 创建相关产品族:适用于需要创建一系列相互关联或依赖的对象的场景,如游戏开发中创建不同主题风格的角色、场景和道具等产品族。
- 跨平台开发:在开发跨平台应用程序时,不同平台(如 Windows、Mac、Linux 等)有各自的界面组件(按钮、文本框等),可以使用抽象工厂模式为每个平台创建对应的产品族,实现界面的统一管理和切换。
相关文章:
C#的简单工厂模式、工厂方法模式、抽象工厂模式
工厂模式是一种创建型设计模式,主要将对象的创建和使用分离,使得系统更加灵活和可维护。常见的工厂模式有简单工厂模式、工厂方法模式和抽象工厂模式,以下是 C# 实现的三个案例: 简单工厂模式 简单工厂模式通过一个工厂类来创建…...
用hexo初始化博客执行hexo init时碰到的问题
用hexo初始化博客执行hexo init时碰到的问题 $ hexo init myblog INFO Cloning hexo-starter https://github.com/hexojs/hexo-starter.git fatal: unable to access https://github.com/hexojs/hexo-starter.git/: SSL certificate problem: unable to get local issuer cer…...
4.1--入门知识扫盲,ISO知识体系介绍(看一遍,协议啥的全部记住)
OSI七层模型:网络世界的"七重天"生存指南(附快递小哥版图解) “如果你觉得网络分层很抽象,那就想象自己在寄快递” —— 来自一个被三次握手逼疯的程序员 开场白:网络通信就像送外卖 假设你要给隔壁妹子送奶…...
AI训练如何获取海量数据,论平台的重要性
引言:数据——AI时代的“新石油” 在人工智能和大模型技术飞速发展的今天,数据已成为驱动技术进步的 “ 燃料 ”。无论是训练聊天机器人、优化推荐算法,还是开发自动驾驶系统,都需要海量、多样化的数据支持。 然而,获…...
Axure高级功能深度解析一一高效原型设计的利器
Axure作为一款专业的原型设计工具,凭借其强大的功能和灵活的交互设计,成为了众多设计师和开发者的首选。本文将深入探讨Axure的高级功能,帮助大家更好地利用这款工具,提升原型设计的效率和质量。 一、Axure高级功能概览 • 变量管…...
QT国产化系统软件开发
一、国产操作系统 1、鸿蒙HarmonyOS NEXT 核心架构 采用自研鸿蒙内核,完全脱离Linux与AOSP代码,基于分布式架构实现跨设备资源虚拟化整合,支持动态调度多终端硬件能力。通过分布式软总线技术(D-Bus)实现低时延…...
Git 使用SSH登陆
一、SSH介绍 SSH连接相比于HTTP连接会简单一点,因为SSH连接通过了私钥与公钥进行身份认证,这样就不需要像HTTP一样,每次clone或者操作仓库都需要输入密码 其中私钥和密钥是需要在自己电脑上生成的,通过命令即可生成一个私钥和一个…...
织梦DedeCMS修改文章【标题、短标题、关键词】长度限制
在后台虽然可以设置标题的长度,但是数据库的字段固定是60个字符,短标题是36字符,关键词30字符,所以这里教大家修改一下织梦DedeCMS修改【标题】【短标题】【关键词】长度限制 一、后台配置 1、进入dede后台管理 -> 系统 ->…...
Powershell WSL部署ubuntu22.04.5子系统
前提条件WSL 安装 wsl 安装参考1wsl 安装csdn参考2wsl 百度网盘离线下载 本地目录安装ubuntu22.04.5 子系统 powershell 管理员打开执行(实现,下载安装ubuntu子系统,用户创建,远程ssh登录设置,防火墙端口开放)子系统IP 查看方法wsl...
umi自带的tailwindcss修改为手动安装
1》为什么改为手动? 主要是为了解决这个报错问题,虽然重新运行也可解决,但是总是要运行2-3次,比较麻烦 2》如何手动 1,先在devDependencies下安装这两个包 pnpm install postcss8.5.1 -D "autoprefixer"…...
Android 13 Launcher3最近任务列表“全部清除“按钮位置优化实战
一、问题背景与实现难点 在Android 13横屏设备开发中,系统默认将最近任务列表的"全部清除"按钮布局在屏幕左侧,这与用户习惯的底部布局存在明显差异。相较于Android 8.1时代SystemUI模块的实现,Android 13将相关逻辑迁移至Launche…...
基于k3s部署Nginx、MySQL、SpringBoot和Redis的详细教程
1. 安装k3s集群 1.1 单节点快速部署 # 使用root或sudo权限执行 curl -sfL https://get.k3s.io | sh -# 验证安装 sudo kubectl get nodes # 输出应为Ready状态 sudo systemctl status k3s1.2 配置kubectl权限(可选) mkdir -p ~/.kube sudo cp /etc/r…...
SQL Server数据库简介及应用
SQL Server以高性能、高可用性著称,支持Windows/Linux跨平台部署,满足混合云需求。其内存优化表、列存储索引加速数据处理,AlwaysOn可用性组保障业务连续性。安全体系集成身份验证与加密,符合企业合规要求。与Azure无缝集成&#…...
麒麟V10 arm cpu aarch64 下编译 RocketMQ-Client-CPP 2.2.0
国产自主可控服务器需要访问RocketMQ消息队列,最新的CSDK是2020年发布的 rocketmq-client-cpp-2.2.0 这个版本支持TLS模式。 用默认的版本安装遇到一些问题,记录一下。 下载Releases apache/rocketmq-client-cpp GitHubhttps://github.com/apache/roc…...
【商城实战(49)】解锁小程序端适配与优化,让商城飞起来
【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配…...
使用码云搭建CocoaPods远程私有库
一、创建远程私有索引库 用来存放私有框架的详细描述信息.podspec文件 1. 创建私有库 假设码云上创建的私有库为repo-spec 2. 查看本地已存在的索引库 pod repo list 3. 将远程私有索引库添加到本地 pod repo add [https://gitee.com/jingluoguo/repo-spec.git](https://gi…...
深度学习有哪些算法?
深度学习包含多种算法和模型,广泛应用于图像处理、自然语言处理、语音识别等领域。以下是主要分类及代表性算法: 一、基础神经网络 多层感知机(MLP) 最简单的深度学习模型,由多个全连接层组成,用于分类和回…...
专访LayaAir引擎最有价值专家-施杨
在 LayaAir 引擎的资源商店中,许多开发者都会注意到一个熟悉的名字——“射手座”。他不仅贡献了大量高质量的 Shader 资源,让一些开发者通过他的作品了解到 LayaAir 引擎在 3D 视觉效果上的更多可能,也让大家能够以低成本直接学习并应用这些…...
AJAX的理解和原理还有概念
你想问的可能是 AJAX(Asynchronous JavaScript and XML) ,它并不是一门新的编程语言,而是一种在无需重新加载整个网页的情况下,能够与服务器进行异步通信并更新部分网页的技术。以下从基本概念、原理、优点、使用场景等…...
自然语言处理:文本聚类
介绍 大家好,博主又来和大家分享自然语言处理领域的知识了。今天给大家分享的内容是自然语言处理中的文本聚类。 文本聚类在自然语言处理领域占据着重要地位,它能将大量无序的文本按照内容的相似性自动划分成不同的类别,极大地提高了文本处…...
RabbitMQ 集群降配
这里写自定义目录标题 摘要检查状态1. 检查 RabbitMQ 服务状态2. 检查 RabbitMQ 端口监听3. 检查 RabbitMQ 管理插件是否启用4. 检查开机自启状态5. 确认集群高可用性6. 检查使用该集群的服务是否做了断开重连 实操1. 负载均衡配置2. 逐个节点降配(滚动操作…...
uniapp工程中解析markdown文件
在uniapp中如何导入markdown文件,同时在页面中解析成html,请参考以下配置: 1. 安装以下3个依赖包 npm install marked highlight.js vite-plugin-markdown 2. 创建vite.config.js配置文件 // vite.config.js import { defineConfig } fro…...
数据结构:二叉树(一)·(重点)
前言 什么树?what? 树的概念与结构 概念: 树是⼀种⾮线性的数据结构,它是由 n ( n>0 ) 个有限结点组成⼀个具有层次关系的集合。 结构: 有⼀个特殊的结点,称为根结点&#…...
DevEco Studio的使用
目录 1.创建ArkTS工程 2.ArkTS工程目录结构(Stage模型) 构建第一个页面 构建第二个页面 实现页面间的跳转 1.创建ArkTS工程 若首次打开DevEco Studio,请点击Create Project创建工程。如果已经打开了一个工程,请在菜单栏选择…...
十七、实战开发 uni-app x 项目(仿京东)- 后端指南
前面我们已经用uniappx进行了前端实战学习 一、实战 开发uni-app x项目(仿京东)-规划-CSDN博客 二、实战 开发uni-app x项目(仿京东)-项目搭建-CSDN博客 三、实战开发 uni-app x 项目(仿京东)- 技术选型-CSDN博客 四、实战开发 uni-app x 项目(仿京东)- 页面设计-C…...
数据开发岗笔试题>>sql(hive) ,excel [2025]
sql SELECT user_id, AVG(loan_amount) AS avg_loan_amount FROM loan GROUP BY user_id HAVING AVG(loan_amount) > 20000; 授信表:credit 字段包含user_id(用户id),credit_id(授信id),credit_time(授信时间yyyy-MM-dd HH:mm:ss)&#x…...
内存模型以及分区,需要详细到每个区放什么。
1. 内存模型以及分区,需要详细到每个区放什么。 JVM 分为堆区和栈区,还有方法区,初始化的对象放在堆里面,引用放在栈里面, class 类信息常量池(static 常量和 static 变量)等放在方法区new: …...
python strip/rstrip/lstrip详细讲解(涵盖许多例子、作用以及复杂行为处理)
python strip/rstrip/lstrip详细讲解: 在Python中,strip、lstrip、rstrip 是用于字符串处理的常用方法,主要功能是去除字符串首尾的指定字符。它们的区别如下: 1. strip([chars]) 作用 :删除字符串开头和结尾 处所有属于 chars 的字符,直到遇到不属于 chars 的字符为止…...
Spring Boot集成PageHelper:轻松实现数据库分页功能
Spring Boot集成PageHelper:轻松实现数据库分页功能 1. 为什么需要分页? 分页是处理大数据量查询的核心技术,其重要性体现在: 性能优化:避免单次查询返回过多数据导致内存溢出或响应延迟。用户体验:前端展…...
OpenGL ES 入门指南:从基础到实战
引言:为什么需要 OpenGL ES? 在当今的嵌入式设备(如智能手机、汽车仪表盘、智能家居中控屏)中,流畅的图形渲染能力是用户体验的核心。OpenGL ES(OpenGL for Embedded Systems) 作为行业标准&am…...
