C# 工厂模式学习

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的接口,而不是通过具体类来实例化对象。工厂模式可以将对象的创建过程封装起来,使代码更具有灵活性和可扩展性。

工厂模式有几种常见的实现方式:

  1. 简单工厂模式(Simple Factory Pattern): 简单工厂模式通过一个工厂类来决定创建哪种具体类的实例。这个工厂类通常提供一个静态方法,根据传入的参数创建相应的对象。

  2. 工厂方法模式(Factory Method Pattern): 工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法使一个类的实例化延迟到其子类。

  3. 抽象工厂模式(Abstract Factory Pattern): 抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而无需明确指定具体类。通过使用抽象工厂模式,一个类可以实例化一组相关对象,而不需要知道它们的具体类。

简单工厂模式示例

假设我们有一个动物园项目,需要创建不同的动物对象:

// 动物接口
public interface IAnimal
{void Speak();
}// 具体的动物类
public class Dog : IAnimal
{public void Speak(){Console.WriteLine("Woof!");}
}public class Cat : IAnimal
{public void Speak(){Console.WriteLine("Meow!");}
}// 简单工厂类
public static class AnimalFactory
{public static IAnimal CreateAnimal(string animalType){switch (animalType.ToLower()){case "dog":return new Dog();case "cat":return new Cat();default:throw new ArgumentException("Unknown animal type");}}
}// 使用示例
class Program
{static void Main(string[] args){IAnimal animal = AnimalFactory.CreateAnimal("dog");animal.Speak();  // 输出:Woof!}
}

工厂方法模式示例

假设我们有一个动物园项目,不同的子类需要创建不同的动物对象:

// 动物接口
public interface IAnimal
{void Speak();
}// 具体的动物类
public class Dog : IAnimal
{public void Speak(){Console.WriteLine("Woof!");}
}public class Cat : IAnimal
{public void Speak(){Console.WriteLine("Meow!");}
}// 工厂接口
public interface IAnimalFactory
{IAnimal CreateAnimal();
}// 具体工厂类
public class DogFactory : IAnimalFactory
{public IAnimal CreateAnimal(){return new Dog();}
}public class CatFactory : IAnimalFactory
{public IAnimal CreateAnimal(){return new Cat();}
}// 使用示例
class Program
{static void Main(string[] args){IAnimalFactory factory = new DogFactory();IAnimal animal = factory.CreateAnimal();animal.Speak();  // 输出:Woof!}
}

抽象工厂模式示例

假设我们有一个动物园项目,需要创建一组相关的对象(例如,动物及其食物):

// 动物接口
public interface IAnimal
{void Speak();
}// 具体的动物类
public class Dog : IAnimal
{public void Speak(){Console.WriteLine("Woof!");}
}public class Cat : IAnimal
{public void Speak(){Console.WriteLine("Meow!");}
}// 食物接口
public interface IFood
{void Get();
}// 具体的食物类
public class DogFood : IFood
{public void Get(){Console.WriteLine("Dog food");}
}public class CatFood : IFood
{public void Get(){Console.WriteLine("Cat food");}
}// 抽象工厂接口
public interface IAnimalFactory
{IAnimal CreateAnimal();IFood CreateFood();
}// 具体工厂类
public class DogFactory : IAnimalFactory
{public IAnimal CreateAnimal(){return new Dog();}public IFood CreateFood(){return new DogFood();}
}public class CatFactory : IAnimalFactory
{public IAnimal CreateAnimal(){return new Cat();}public IFood CreateFood(){return new CatFood();}
}// 使用示例
class Program
{static void Main(string[] args){IAnimalFactory factory = new DogFactory();IAnimal animal = factory.CreateAnimal();IFood food = factory.CreateFood();animal.Speak();  // 输出:Woof!food.Get();      // 输出:Dog food}
}

以上是三种工厂模式的基本示例,可以根据具体需求选择合适的工厂模式来实现代码的创建和管理。如果希望在增加新动物类型时尽量减少对现有类的修改,推荐使用工厂方法模式。工厂方法模式的设计使得每新增一种动物,只需增加一个对应的工厂类和具体的动物类,而无需修改已有的代码,从而符合开闭原则(即对扩展开放,对修改关闭)。

使用工厂方法模式

下面是一个更完善的工厂方法模式示例,展示了如何在增加新动物时,尽量减少对现有代码的修改。

// 动物接口
public interface IAnimal
{void Speak();
}// 具体的动物类
public class Dog : IAnimal
{public void Speak(){Console.WriteLine("Woof!");}
}public class Cat : IAnimal
{public void Speak(){Console.WriteLine("Meow!");}
}// 新增的动物类
public class Bird : IAnimal
{public void Speak(){Console.WriteLine("Tweet!");}
}// 工厂接口
public interface IAnimalFactory
{IAnimal CreateAnimal();
}// 具体工厂类
public class DogFactory : IAnimalFactory
{public IAnimal CreateAnimal(){return new Dog();}
}public class CatFactory : IAnimalFactory
{public IAnimal CreateAnimal(){return new Cat();}
}// 新增的动物工厂类
public class BirdFactory : IAnimalFactory
{public IAnimal CreateAnimal(){return new Bird();}
}// 使用示例
class Program
{static void Main(string[] args){List<IAnimalFactory> factories = new List<IAnimalFactory>{new DogFactory(),new CatFactory(),new BirdFactory()  // 新增的工厂只需在这里添加};foreach (var factory in factories){IAnimal animal = factory.CreateAnimal();animal.Speak();}}
}

在这个示例中,新增一种动物只需:

  1. 创建新的具体动物类,例如 Bird
  2. 创建对应的工厂类,例如 BirdFactory
  3. 在使用的地方添加新的工厂实例,例如在 factories 列表中添加 new BirdFactory()

这样做的好处是每增加一个新动物类型,不需要修改现有的工厂类或具体的动物类,只需要添加新的类和工厂即可,从而降低了代码修改的风险和复杂度。

使用反射和配置来进一步减少修改

如果希望在增加动物时连代码都不需要改动,可以考虑使用反射和配置文件的方式。通过配置文件定义动物类型和对应的工厂类,然后使用反射动态加载:

// 动物接口和具体的动物类(同上)// 工厂接口和具体工厂类(同上)// 使用反射加载工厂类
class Program
{static void Main(string[] args){// 假设配置文件中定义了动物类型和对应的工厂类var factoryTypes = new List<string>{"DogFactory","CatFactory","BirdFactory"  // 配置文件中新增的工厂类};var factories = new List<IAnimalFactory>();foreach (var factoryType in factoryTypes){var type = Type.GetType(factoryType);if (type != null && typeof(IAnimalFactory).IsAssignableFrom(type)){var factory = (IAnimalFactory)Activator.CreateInstance(type);factories.Add(factory);}}foreach (var factory in factories){IAnimal animal = factory.CreateAnimal();animal.Speak();}}
}

接口与继承结合使用

工厂模式主要使用了接口、继承,在C#中,接口和继承是面向对象编程的重要概念。接口定义了一组方法和属性,而继承允许一个类从另一个类继承其成员。接口可以实现多重继承,而类只能继承一个基类。通常情况下,接口和继承可以结合使用,以充分利用它们各自的优点。通过这种方式,基类可以提供一些通用的实现,而接口可以定义特定的行为。

// 接口
public interface IAnimal
{void Speak();void Eat();
}// 基类
public class Animal
{public void Sleep(){Console.WriteLine("Sleeping...");}
}// 派生类实现接口
public class Dog : Animal, IAnimal
{public void Speak(){Console.WriteLine("Woof!");}public void Eat(){Console.WriteLine("Dog is eating.");}
}public class Cat : Animal, IAnimal
{public void Speak(){Console.WriteLine("Meow!");}public void Eat(){Console.WriteLine("Cat is eating.");}
}// 使用示例
class Program
{static void Main(string[] args){IAnimal dog = new Dog();dog.Speak(); // 输出:Woof!dog.Eat();   // 输出:Dog is eating.IAnimal cat = new Cat();cat.Speak(); // 输出:Meow!cat.Eat();   // 输出:Cat is eating.// 使用基类方法Animal animalDog = (Animal)dog;animalDog.Sleep(); // 输出:Sleeping...Animal animalCat = (Animal)cat;animalCat.Sleep(); // 输出:Sleeping...}
}

总结

  • 接口:定义了一组必须实现的方法和属性,没有实现代码。支持多重继承,使得类可以实现多个接口。
  • 继承:用于从现有类创建新类,继承基类的成员。每个类只能有一个基类,但可以实现多个接口。
  • 结合使用:通过将接口和继承结合使用,可以实现代码的高复用性和灵活性。

通过上述示例,可以看到如何使用接口和继承来设计灵活且可扩展的应用程序结构。这样既能充分利用基类的通用功能,又能通过接口实现特定的行为。

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

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

相关文章

Go 如何通过 Kafka 客户端库 生产与消费消息

文章目录 0.前置说明1. confluent-kafka-go2. sarama3. segmentio/kafka-go4. franz-go选择建议 1.启动 kafka 集群2.安装 confluent-kafka-go 库3.创建生产者特殊文件说明如何查看.log文件内容 4.创建消费者 0.前置说明 Go 语言中有一些流行的 Kafka 客户端库。以下是几个常用…

【Uniapp小程序】自定义导航栏uni-nav-bar滚动渐变色

效果图 新建activityScrollTop.js作为mixins export default {data() {return {navBgColor: "rgba(0,0,0,0)", // 初始背景颜色为完全透明navTextColor: "rgba(0,0,0,1)", // 初始文字颜色};},onPageScroll(e) {// 设置背景const newAlpha Math.min((e.s…

踩坑:6年后为何不用GraphQL了?

GraphQL 是一项令人难以置信的技术&#xff0c;自从我在 2018 年首次开始将其投入生产以来&#xff0c;它就吸引了很多人的注意力。 在一大堆无类型的 JSON REST API 上构建了许多 React SPA 之后&#xff0c;我发现 GraphQL 是一股清新的空气。 然而&#xff0c;随着时间的推…

mybatis用map接收返回对象,不想让数据类型为tinyint自动转换为boolean,如何处理

在 MyBatis 中&#xff0c;当使用 Map 来接收查询结果时&#xff0c;MyBatis 会根据列的数据类型自动选择合适的 Java 类型来映射这些值。默认情况下&#xff0c;如果数据库列是 TINYINT(1)&#xff0c;MyBatis 可能会错误地将其映射为 boolean&#xff0c;因为它经常被误解为只…

PPP认证两种:PAP和CHAP,两次握手和三次握手

CHAP&#xff08;Challenge-Handshake Authentication Protocol&#xff0c;质询握手认证协议&#xff09;的设计理念是增强网络认证过程的安全性。在CHAP的三次握手过程中&#xff0c;不直接传送用户的明文密码&#xff0c;以此来提高安全性&#xff0c;具体步骤如下&#xff…

开源大模型源代码

开源大模型的源代码可以在多个平台上找到&#xff0c;以下是一些知名的开源大模型及其源代码的获取方式&#xff1a; 1. **艾伦人工智能研究所的开放大语言模型&#xff08;Open Language Model&#xff0c;OLMo&#xff09;**&#xff1a; - 提供了完整的模型权重、训练代…

springboot结合mybatis使用多数据源的方式

背景 最近有一个需求&#xff0c;有两个库需要做同步数据&#xff0c;一个Doris库&#xff0c;一个mysql库&#xff0c;两边的表结构一致&#xff0c;这里不能使用navicat等工具提供的数据传输之类的功能&#xff0c;只能使用代码做同步&#xff0c;springboot配置多数据…

如何设置手机的DNS

DNS 服务器 IP 地址 苹果 华为 小米 OPPO VIVO DNS 服务器 IP 地址 中国大陆部分地区会被运营商屏蔽网络导致无法访问&#xff0c;可修改手机DNS解决。 推荐 阿里的DNS (223.5.5.5&#xff09;或 114 (114.114.114.114和114.114.115.115) 更多公开DNS参考&#xff1a; 苹果…

ESP32-C3模组上实现蓝牙BLE配网功能(1)

本文内容参考&#xff1a; 《ESP32-C3 物联网工程开发实战》 乐鑫科技 蓝牙的名字由来是怎样的&#xff1f;为什么不叫它“白牙”&#xff1f; 特此致谢&#xff01; 一、蓝牙知识基础 1. 什么是蓝牙&#xff1f; &#xff08;1&#xff09;简介 蓝牙技术是一种无线数据和…

【缓存】OS层面缓存设计机制

操作系统的缓存设计机制是计算机体系结构中的一个重要组成部分&#xff0c;旨在提高系统的性能&#xff0c;特别是通过减少对慢速存储设备&#xff08;如硬盘&#xff09;的访问次数来加速数据的读取和写入。 以下是一些常见的操作系统缓存设计机制&#xff1a; CPU缓存&…

web学习笔记(六十一)

目录 如何使用公共组件来编写页面 如何使用公共组件来编写页面 1.导入公共组件nav.vue import Catenav from "/components/nav.vue"; 2.在页面插入子组件 如果使用了setup语法糖此时就可以直接在页面插入 <Catenav ></Catenav>标签&#xff0c; …

.NET 快速重构概要1

1.封装集合 在某些场景中,向类的使用者隐藏类中的完整集合是一个很好的做法,比如对集合的 add/remove 操作中包 含其他的相关逻辑时。因此,以可迭代但不直接在集合上进行操作的方式来暴露集合,是个不错的主意。 public class Order { private int _orderTotal; private Li…

Camunda BPM架构

Camunda BPM既可以单独作为流程引擎服务存在,也能嵌入到其他java应用中。Camunda BPM的核心流程引擎是一个轻量级的模块,可以被Spring管理或者加入到自定义的编程模型中,并且支持线程模型。 1,流程引擎架构 流程引擎由多个组件构成,如下所示: API服务 API服务,允许ja…

逻辑回归分类算法

文章目录 算法推导 线性回归解决连续值的回归预测&#xff1b;而逻辑回归解决离散值的分类预测&#xff1b; 算法推导 逻辑回归可以看作是两部分&#xff0c;以0、1分类问题说明&#xff1b; 线性回归部分 对于一个样本 x i x_i xi​&#xff0c;有n个特征 x i ( 1 ) x_i^{(1)…

蒙自源儿童餐新品上市,引领健康美味新潮流

随着夏日的热烈与儿童节的欢乐氛围到来&#xff0c;蒙自源品牌隆重推出儿童餐新品&#xff0c;以“快乐不分大小&#xff0c;谁还不是个宝宝”为主题&#xff0c;为广大消费者带来一场健康与美味的盛宴。新品上市活动将于5月25日举行&#xff0c;蒙自源将以其独特的产品魅力和创…

install

目录 1、 install 1.1、 //creates form with validation 1.2、 onStepChanging: function (event, currentIndex, newIndex) { 1.3、 onFinishing: function (event, currentIndex) { 1.4、 //init inst

最新 HUAWEI DevEco Studio 调试技巧

最新 HUAWEI DevEco Studio 调试技巧 前言 在我们使用 HUAWEI DevEco Studio 编辑器开发鸿蒙应用时&#xff0c;免不了要对我们的应用程序进行代码调试。我们根据实际情况&#xff0c;一般会用到以下三种方式进行代码调试。 肉眼调试法注释排错调试法控制台输出法弹出提示法断…

【算法实战】每日一题:将某个序列中内的每个元素都设为相同的值的最短次数(差分数组解法,附概念理解以及实战操作)

题目 将某个序列中内的每个元素都设为相同的值的最短次数 1.差分数组&#xff08;后面的减去前面的值存储的位置可以理解为中间&#xff09; 差分数组用于处理序列中的区间更新和查询问题。它存储序列中相邻元素之间的差值&#xff0c;而不是直接存储每个元素的值 怎么对某…

STM32 入门教程(江科大教材)#笔记2

3-4按键控制LED /** LED.c**/ #include "stm32f10x.h" // Device headervoid LED_Init(void) {/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_I…

关系数据库:关系运算

文章目录 关系运算并&#xff08;Union&#xff09;差&#xff08;Difference&#xff09;交&#xff08;Intersection&#xff09;笛卡尔积&#xff08;Extended Cartesian Product&#xff09;投影&#xff08;projection&#xff09;选择&#xff08;Selection&#xff09;除…