工厂模式应用实例

引言

设计模式概念

设计模式(Design Pattern)的官方概念可以表述为:在软件设计中,设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它是针对特定问题或特定场景的解决方案,是一种经过实践验证的最佳实践。设计模式主要用于解决软件设计中的各种问题,例如代码重复、性能问题、可维护性和可扩展性等。使用设计模式可以创建出可重用的解决方案,使代码更加清晰易懂、易维护和易扩展。设计模式不是语言特性或库,而是一种思想、一种方法论,它可以被应用于各种编程语言和框架中。学习设计模式可以提高设计能力和编程水平。

工厂模式概念:

工厂模式(Factory Pattern)是 最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的  最佳  方式。

工厂模式提供了一种创建对象的方式,而 无需指定要创建的具体类。

工厂模式属于创建型模式,它在创建对象时提供了一种封装机制,将实际创建对象的代码与使用代码分离。

特点:

创建对象时,- 会对客户端暴露创建逻辑,并且是 通过 使用同一接口(API) 来指向新创建的对象

工厂模式的优势

工厂模式的优势主要体现在以下几个方面:

  1. 解耦:工厂模式将对象的创建与使用分离,使得代码结构更加清晰。当需要创建新的对象时,无需修改使用对象的代码,只需修改工厂类即可,这大大降低了代码的耦合度。

  2. 封装性:工厂模式隐藏了对象的创建细节,使用者只需知道所需对象的接口,而无需知道具体的创建过程。这增强了系统的封装性,使得代码更加易于理解和维护。

  3. 可扩展性:当需要添加新的产品时,只需在工厂类中增加一个新的产品创建方法,并修改返回类型或添加新的工厂子类,而无需修改使用对象的代码。这使得系统更加易于扩展。

  4. 灵活性:工厂模式可以根据不同的条件创建不同的对象实例。例如,可以通过配置文件或参数化工厂方法来创建不同的对象,这使得系统更加灵活。

  5. 符合开闭原则:工厂模式符合开闭原则,即对于扩展是开放的,对于修改是封闭的。当需要添加新的产品时,只需扩展工厂类而无需修改已有代码。

  6. 简化代码:通过工厂模式,可以将复杂的创建过程封装在工厂类中,从而简化使用对象的代码。同时,工厂模式还可以减少代码中的重复部分,提高代码的可重用性。

  7. 便于测试:工厂模式可以将创建对象的代码与使用对象的代码分离,这使得在测试过程中可以更容易地模拟或替换对象实例,从而便于进行单元测试或集成测试。

总之,工厂模式通过解耦、封装、可扩展性、灵活性、开闭原则、简化代码和便于测试等优势,使得系统更加易于理解维护扩展测试

工厂模式实现

(以下代码为例):

混乱的单文件代码


#include <stdio.h>//  结构体实现类 -- 抽象
struct Animal
{//  成员属性char name[128];int age;int sex;// 成员方法// 注意这里是函数指针, if 不加上(), 就变成了返回值是 void*void (*peat)();void (*pbeat)();
};void dogEat()
{puts("狗吃屎");
}void catEat()
{puts("猫吃鱼");
}void personEat()
{puts("人吃米");
}void dogBeat()
{puts("d四你");
}void catBeat()
{puts("c四你");
}void personBeat()
{puts("p四你");
}int main()
{//简单的赋值方式struct Animal dog = {.peat = dogEat,.pbeat = dogBeat}; struct Animal cat = { .peat = catEat,.pbeat = catBeat}; struct Animal person = {  .peat = personEat,.pbeat = personBeat}; dog.peat();cat.peat();person.peat();dog.pbeat();cat.pbeat();person.pbeat();return 0;
}

工厂模式设计图: 


封装各个函数 


记得把 main 函数需要 用到 .c(源文件)里面的函数,在需要包含的.h(头文件)中声明,不然 在main里面不能调用到


====================================
以下是全部文件

main.c

#include <string.h>#include "animal.h"// 链表的查找
struct Animal*findUtilByName(char *str,struct Animal*phead)
{struct Animal* p = phead;if(NULL == phead){puts("空链表");return NULL;}else{while(NULL != p){if(strcmp(p->name,str) == 0){return  p;}p = p->next;}}return NULL;}int main()
{char buf[128] ={'\0'};struct Animal* phead = NULL;struct Animal* ptmp;//将我们需要的三种对象加入到链表中 phead = putCatToLink(phead);phead = putdogToLink(phead);phead = putpersonToLink(phead);while (1) // 这就算我们需要实现的业务{puts("请选择你需要的对象,包括:Tom, huang, likui");scanf("%s",buf);ptmp = findUtilByName(buf,phead);if(NULL != ptmp){ptmp->peat();ptmp->pbeat();}memset(buf,'\0',sizeof(buf));}return 0;
}

==============================================


animal.h

#ifndef __ANIMAL_H_
#define __ANIMAL_H_#include <stdio.h>struct Animal
{//  成员属性char name[128];int age;int sex;// 成员方法// 注意这里是函数指针, if 不加上(), 就变成了返回值是 void*void (*peat)();void (*pbeat)();struct Animal * next; //我们使用链表来遍历所有对象
};struct  Animal *putpersonToLink(struct  Animal *phead);
struct  Animal * putdogToLink(struct  Animal *phead);
struct  Animal * putCatToLink(struct  Animal *phead);#endif


==============================================


cat.c

#include "animal.h"void catEat()
{puts("猫吃鱼");
}void catBeat()
{puts("挠四你");
}
// 这里面的赋值 用到的函数 需要在前面先定义, 注意位置不能错
struct Animal cat = {.name = "Tom",.peat = catEat,.pbeat = catBeat};// 头插法  -- 向链表中添加猫对象struct  Animal * putCatToLink(struct  Animal *phead)
{
//    if(NULL == phead)
//    {
//     phead = &cat; 
//    }
//    else
//    {
//     cat.next = phead;
//     phead = &cat;
//    }if(NULL != phead)    //if链表里面已经有数据的话cat.next = phead; // 把cat插入头节点的后面
phead = &cat; //空链表 cat 就作为头 | 非空 cat 插入到头节点后面之后也会成为新的头return phead;
}

==============================

dog.c

#include "animal.h"void dogEat()
{puts("狗吃屎");
}void dogBeat()
{puts("咬四你");
}
struct Animal dog = {.name = "huang",.peat = dogEat,.pbeat = dogBeat};// 头插法  -- 向链表中添加猫对象struct  Animal * putdogToLink(struct  Animal *phead)
{if(NULL != phead)    //if链表里面已经有数据的话dog.next = phead; // 把dog插入头节点的后面
phead = &dog; //空链表 dog 就作为头 | 非空 dog 插入到头节点后面之后也会成为新的头return phead;
}


person.c

#include "animal.h"
#include <stdio.h>void personEat()
{puts("人吃米");
}void personBeat()
{puts("骂四你");
}struct Animal person = {.name = "likui",.peat = personEat,.pbeat = personBeat};// 头插法  -- 向链表中添加猫对象struct  Animal *putpersonToLink(struct  Animal *phead)
{if(NULL != phead)    //if链表里面已经有数据的话person.next = phead; // 把person插入头节点的后面
phead = &person; //空链表 person 就作为头 | 非空 person 插入到头节点后面之后也会成为新的头return phead;
}

// if 我们需要 扩展功能 --> 比如添加对象

这时候工厂 模式优势就体现出来了

常见问题:


fish.c:22:18: error: conflicting types for ‘putfishToLink’; have ‘struct Animal *(struct Animal *)’
   22 | struct  Animal * putfishToLink(struct  Animal *phead)  --> 这种报错通常是 源文件改了,但是头文件没有改


==========================


扩展 

 添加 fish.c
#include "animal.h"void fishEat()
{puts("大鱼小鱼");
}void fishBeat()
{puts("吐泡泡");
}
struct Animal fish = {.name = "dayu",.peat = fishEat,.pbeat = fishBeat};// 头插法  -- 向链表中添加猫对象struct  Animal * putfishToLink(struct  Animal *phead)
{if(NULL != phead)    //if链表里面已经有数据的话fish.next = phead; // 把fish插入头节点的后面
phead = &fish; //空链表 fish 就作为头 | 非空 fish 插入到头节点后面之后也会成为新的头return phead;
}

//然后我们只需要修改.h 头文件中包含的函数, 和main里面的逻辑
// 我们发现添加一次动物我们就需要去选项输出一次名字不太友好,那么我们可以优化遍历链表输出


新的main.c :
#include <string.h>#include "animal.h"// 链表的查找
struct Animal*findUtilByName(char *str,struct Animal*phead)
{struct Animal* p = phead;if(NULL == phead){puts("空链表");return NULL;}else{while(NULL != p){if(strcmp(p->name,str) == 0){return  p;}p = p->next;}}return NULL;}void getAllName(struct Animal*phead){struct Animal* p = phead;if(NULL == phead){puts("空链表");}else{while(NULL != p){printf("%s ",p->name);p = p->next;}}}int main()
{char buf[128] ={'\0'};struct Animal* phead = NULL;struct Animal* ptmp;//将我们需要的三种对象加入到链表中 phead = putCatToLink(phead);phead = putdogToLink(phead);phead = putpersonToLink(phead);phead = putfishToLink(phead);while (1) // 这就算我们需要实现的业务{puts("请选择你需要的对象,包括:");getAllName(phead);scanf("%s",buf);ptmp = findUtilByName(buf,phead);if(NULL != ptmp){ptmp->peat();ptmp->pbeat();}memset(buf,'\0',sizeof(buf));}return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

04-22 周日 阿里云-瑶光上部署FastBuild过程(配置TLS、自定义辅助命令)

04-22 周日 阿里云-瑶光上部署FastBuild过程 时间版本修改人描述2024年4月22日14:18:59V0.1宋全恒新建文档2024年4月23日20:41:26V1.0宋全恒完成了基本流程的添加 简介 前提 准备两台服务&#xff0c;一台部署Docker&#xff0c;一台部署FastBuild的镜像容器服务所述的Docke…

最高20K/月,安全、数通、云计算多个方向急招,可内推!

高级安全工程师【岗位职责及要求】 1、统筹负责行业客户的安全项目交付&#xff0c;能够独自输出技术方案并完成施&#xff0c;并具备指导初中级工程师实施的能力&#xff1b; 2、掌握H3C全系列安全产品功能并对全系列产品原理有深入了解&#xff0c;能够熟练完成安全产品规划及…

Spring IoCDI(3)—DI详解

目录 一、属性注入 二、构造方法注入 小结&#xff1a;构造函数的注入 三、Setter注入 四、三种注入的优缺点分析&#xff08;面试题&#xff09; 1、属性注入 优点&#xff1a; 缺点&#xff1a; 2、构造方法注入&#xff08;Spring4.X推荐&#xff09; 优点&#x…

python数据分析-老龄化分析

一、研究背景介绍和分析安排 中国作为世界上人口最多的国家&#xff0c;其人口结构的变化对国内外经济都有着深远的影响。近年来&#xff0c;中国的老龄人口比例不断上升&#xff0c;这一变化引起了广泛的社会关注和政策讨论。老龄化带来的挑战包括劳动力市场紧缩、养老金负担…

Innodb实现的索引

概念 一种用于提高数据库查询性能的有序的数据结构。通过使用索引&#xff0c;数据库引擎可以快速定位到存储表中的特定数据&#xff0c;而不必逐行遍历整个表。在处理大量数据的时候可以显著加快数据检索的速度。 通过索引列队数据进行排序&#xff0c;降低数据排序的成本&a…

英语学习笔记4——Is this your ...?

Is this your …? 词汇 Vocabulary suit /sut/ n. 西装&#xff0c;正装 suit 的配套&#xff1a; shirt n. 衬衫tie n. 领带&#xff0c;领结belt n. 腰带trousers n. 裤子shoes n. 鞋子 school /skuːl/ n. 学校 所有学校 搭配&#xff1a;middle school 初中    hig…

C++笔记:类与对象(三)->多态

多态 虚函数 先来看一段代码&#xff1a; #include<iostream> using namespace std;class Animal { public :void run() {cout << "I dont know how to run" << endl;} };class Cat : public Animal{ public :void run() {cout << "I …

Elsevier旗下双1区TOP刊,8.8分影响因子加上超低自引率,各指标领跑计算机类SCI

【SciencePub学术】 今天小编给大家带来了一本计算机类的高分优刊解读&#xff0c;隶属于Elsevier出版社&#xff0c;JCR1区&#xff0c;中科院1区TOP&#xff0c;影响因子高达8.7&#xff0c;领域相符的学者可考虑&#xff01; APPLIED SOFT COMPUTING 1 期刊概况 【期刊简…

SD-WAN对云服务的优化

在云服务日益普及的当下&#xff0c;SD-WAN技术正成为众多企业优化网络连接的首选方案。其通过优化云集成和连接&#xff0c;以及增强应用程序性能&#xff0c;为企业带来了前所未有的业务效益。这种革新性的云连接方式极大地促进了企业对全球劳动力和潜在客户的触达能力。 软件…

【设计模式实战】用三种设计模式去优化if-else屎山代码!!!

优化前提 【设计模式】之策略模式【设计模式】之工厂模式&#xff08;三种&#xff09;【设计模式】之模板方法模式 前言 我们之前也学习了不少设计模式&#xff0c;今天给大家介绍一个案例&#xff0c;帮助大家更加熟悉设计模式&#xff0c;并能够在自己写项目的时候能够下意…

PXE远程部署CentOS系统

文章目录 在局域网内搭建PXE服务器PXE 启动组件PXE的优点实验一、搭建PXE服务器&#xff0c;实现远程部署CentOS系统环境准备server关闭防火墙安装组件准备 Linux 内核、初始化镜像文件及PXE引导文件配置启用TFTP 服务配置启动DHCP服务准备CentOS 7 安装源配置启动菜单文件 Cli…

centos7.9系统rabbitmq3.8.5升级为3.8.35版本

说明 本文仅适用rabbitmq为RPM安装方式。 升级准备 查看环境当前版本&#xff1a; # cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) # rabbitmqctl status Status of node rabbitmq01 ... RuntimeOS PID: 19333 OS: Linux Uptime (seconds): 58 Is under …

解决本地启动项目,用IP地址访问失败问题

解决方法&#xff1a;看看index.html页面有没有 这个标签&#xff0c;将它注释掉

Go 语言基础之指针、复合类型【数组、切片、指针、map、struct】

1、数组 特别需要注意的是&#xff1a;在 Go 语言中&#xff0c;数组长度也是数组类型的一部分&#xff01;所以尽管元素类型相同但是长度不同的两个数组&#xff0c;它们的类型并不相同。 1.1、数组的初始化 1.1.1、通过初始化列表{}来设置值 var arr [3]int // int类型的数…

获取波形极值与间距并显示

获取并显示波形的极值与极值间距 1、流程 1、通过signal.find_peaks获取极大值 2、获取极大值下标 3、获取极大值对应的值 4、获取极大值的下标间距(就是隔多远有一个极大值) 5、获取极大值间距的标准差、方差、均值、最大值 6、图形展示波形图并标记极大值2、效果图 3、示…

专项技能训练五《云计算网络技术与应用》实训8-1:建立基于OpenvSwitch的GRE隧道

文章目录 建立基于OpenvSwitch的GRE隧道1. 使用VMware安装2个CentOS 7虚拟机&#xff0c;安装时记得都开启CPU虚拟化&#xff0c;第一台命名为“Docker”&#xff0c;第二台命名为“KVM”。2. 安装完虚拟机后&#xff0c;进入虚拟机&#xff0c;修改网络配置&#xff08;onboot…

软件架构的艺术:探索演化之路上的18大黄金原则

实际工作表明&#xff0c;一步到位的设计往往不切实际&#xff0c;而演化原则指导我们逐步优化架构&#xff0c;以灵活响应业务和技术的变化。这不仅降低了技术债务和重构风险&#xff0c;还确保了软件的稳定性和可扩展性。同时&#xff0c;架构的持续演进促进了团队协作&#…

新华三VRRP配置

新华三VRRP配置 配置步骤 (1).基础配置&#xff1a; CORE1&#xff1a; [CORE1]vlan 10 //创建vlan10 [CORE1-vlan10]int vlan 10 //进入vlanif 10 [CORE1-Vlan-interface10]ip add 192.168.10.1 24 //配置ip [CORE1-Vlan-interface10]int g1/0/2 //进入接口 [C…

常见错误以及如何纠正它们

团队和关键结果目标 (OKR) 之间的关系是深刻且至关重要的。总而言之&#xff0c;一切都应该是相互关联的。正如《团队的智慧》一书中所强调的&#xff1a; 在团队中&#xff0c;没有什么比每个成员对共同目标和一组相关绩效目标的承诺更重要的了&#xff0c;而团队对此负有共同…

通过管理系统进行升级怎么选?

现在通过系统来做办公效率提升的又很多&#xff0c;但怎么选&#xff0c;确实很关键。 我们是在去年年初的时候进行企业系统化的。当时刚摘下口罩&#xff0c;领导也是意识到团队办公的不便&#xff0c;数据管理的混乱&#xff0c;业务流转的低效等原因&#xff0c;开始寻找各…