工厂模式应用实例

引言

设计模式概念

设计模式(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://www.mzph.cn/pingmian/9609.shtml

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

相关文章

你写的每条SQL都是全表扫描吗

你写的每条SQL都是全表扫描吗&#xff1f;如果是&#xff0c;那MySQL可太感谢你了&#xff0c;每一次SQL执行都是在给MySQL上压力、上对抗。MySQL有苦难言&#xff1a;你不知道索引吗&#xff1f;你写的SQL索引都失效了不知道吗&#xff1f;慢查询不懂啊&#xff1f;建那么多索…

进一步解读英伟达 Blackwell 架构、NVlink及GB200 超级芯片

2024年3月19日&#xff0c;英伟达CEO黄仁勋在GTC大会上公布了新一代AI芯片架构BLACKWELL&#xff0c;并推出基于该架构的超级芯片GB200&#xff0c;将助推数据处理、工程模拟、电子设计自动化、计算机辅助药物设计、量子计算和生成式 AI 等领域。 为了纪念杰出的数学家David H…

设计软件有哪些?渲染软件篇(3),渲染100邀请码1a12

今天我们继续介绍几款渲染软件&#xff0c;方便大家了解 1、渲染100(http://www.xuanran100.com/?ycode1a12) 渲染100是网渲平台&#xff0c;为设计师提供高性能的渲染服务。通过它设计师可以把本地渲染移到云端进行&#xff0c;速度快价格便宜&#xff0c;支持3dmax、vray、…

文献速递:深度学习医学影像心脏疾病检测与诊断--基于迁移学习的生成对抗网络用于静态和动态心脏PET的衰减校正

Title 题目 Transfer learning‑based attenuation correction for static and dynamic cardiac PET using a generative adversarial network 基于迁移学习的生成对抗网络用于静态和动态心脏PET的衰减校正 01 文献速递介绍 心脏正电子发射断层扫描&#xff08;PET&#xf…

2024数维杯C题成品文章代码思路分享保姆级

天然气水合物资源评估与钻井位置优化&#xff1a;方法、挑战 摘要 天然气水合物&#xff0c;通常称为可燃冰&#xff0c;是一种在特定高压低温条件下由天然气和水形成的类冰结晶物。由于其外观类似冰块且可燃&#xff0c;天然气水合物在深海底及永久冻土区广泛分布&#xff0c;…

数据结构05:树与二叉树 习题01[C++]

考研笔记整理&#xff0c;本篇作为树与二叉树的基本概念习题&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 之前的博文链接在此&#xff1a;数据结构05&#xff1a;树与二叉树[C]-CSDN博客~&#x1f95d;&#x1f95d; 第1版&#xff1a;王道书的课后习题~&#x1…

React + 项目(从基础到实战) -- 第11期

目标 问卷编辑器的开发 设计UI - 拆分布局 水平垂直居中 画布 y方向滚动 自定义问卷组件 后端 返回组件数据 //获取单个问卷信息{url: /api/question/:id,method: get,response: () > {return {errno: 0,data: {id: Random.id(),title: Random.ctitle(),componentList:[//…

蒸汽工厂的新翼:数字孪生锅炉引领未来

在飞速发展的工业4.0时代&#xff0c;数字孪生技术已经深入到我们生产生活的方方面面。而对于那些承载着重工业血脉的蒸汽工厂来说&#xff0c;一项新的技术正在悄然改变它们的未来。 走进蒸汽工厂&#xff0c;感受传统与现代的交融 蒸汽工厂&#xff0c;这个充满力量与热情的…

马化腾用了一年多的时间,告诉所有人,视频号小店是新风口!

大家好&#xff0c;我是电商笨笨熊 当腾讯说出自己要做电商的时候&#xff0c;所有人都在说&#xff0c;根本不可能&#xff1b; 甚至在视频号小店正式推出之后&#xff0c;依旧有人说&#xff0c;腾讯做电商就是笑话&#xff1b; 一个“抄”过来的项目&#xff0c;毫无特色…

Kubernetes容器技术详解

kubernetes Kubernetes&#xff08;K8s&#xff09;由Google打造&#xff0c;是一款功能强大、灵活可扩展的容器编排平台&#xff0c;引领云原生技术潮流。 Kubernetes主要解决以下4大点&#xff1a; 1.自动化运维平台 如下图所示&#xff1a; Kubernetes携手Docker&#xf…

探秘未来科技:数字化无人巡检的奇妙之旅

嘿&#xff0c;朋友们&#xff01;下午茶时间到&#xff01;趁着这会儿咱们来聊一个超级炫酷的话题——数字化无人巡检。想象一下&#xff0c;那些曾经需要人工跋山涉水、风吹日晒的巡检工作&#xff0c;现在正被一群“智能小分队”悄悄接手&#xff0c;是不是觉得既神奇又方便…

25岁软件工程师:19岁创业,25岁创建自己的工作室,谈一下我对创业的一点思考。

文章目录 &#x1f95d;About Me&#x1f3c0;关于工作室✅我对创业思考 大家好哈&#xff0c;欢迎查看工程师令狐本期节目。这篇文章主要是一篇回忆复盘总结文&#xff0c;复盘总结刚上大学到走向工作这段经历&#xff0c;自己的感悟、感想与收获&#xff0c;期望对读者有所帮…

安防监控/视频汇聚系统EasyCVR+AI智能分析助力解决校园霸凌事件

一、方案背景 校园霸凌这一校园中不应存在的现象&#xff0c;却屡见不鲜&#xff0c;它像一把锋利的刀&#xff0c;深深地刺入那些无辜的心灵&#xff0c;让受害者承受着无尽的痛苦。随着科技的进步与发展&#xff0c;我们应该追求有效、进步的手段来阻止校园霸凌事件的发生&a…

解决 Git拉取代码和本地代码丢失问题

git拉取代码&#xff0c;本地写的代码全部为空了&#xff0c;当时都蒙了&#xff0c;最后解决办法是找到对应文件的历史记录 举例&#xff1a;以本地的demo举例&#xff0c;不管是否有git或svn控制&#xff0c;都可以找到历史记录 解决办法&#xff1a; 1、对代码丢失的文件 …

【算法】Dijkstra求最短路算法

TOP提示&#xff1a;Dijkstra算法只适用于不含负权边的情况 Dijkstra算法是一个基于贪心&#xff0c;广搜和动态规划 求图中某点到其他所有点的最短路径的算法 一、步骤 首先我们先总结Dijkstra算法的完整步骤 我们需要一个dis数组存储从起点到达其他节点的最短距离&…

CSS学习笔记之中级教程(一)

1、CSS 布局 - display 属性 1.1 display 属性 display 属性是用于控制布局的最重要的 CSS 属性。 display 属性规定是否/如何显示元素。 每个 HTML 元素都有一个默认的 display 值&#xff0c;具体取决于它的元素类型。大多数元素的默认 display 值为 block 或 inline。 …

每日OJ题_记忆化搜索②_力扣62. 不同路径(三种解法)

目录 力扣62. 不同路径 解析代码1_暴搜递归&#xff08;超时&#xff09; 解析代码2_记忆化搜索 解析代码3_动态规划 力扣62. 不同路径 62. 不同路径 难度 中等 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器…

【MySQL数据库】详解数据库审核工具SQLE的部署及接口调用

SQLE部署及使用 1. 部署SQLE SQLE相信大家都不陌生吧&#xff0c;它是一款开源&#xff0c;支持多场景审核&#xff0c;支持标准化上线流程&#xff0c;原生支持 MySQL 审核且数据库类型可扩展的 SQL审核工具。我们可以基于此工具进行数据库SQL审核&#xff0c;提升SQL脚本质量…

视频怎么打水印?6个软件教你快速进行视频水印制作

视频怎么打水印&#xff1f;6个软件教你快速进行视频水印制作 添加水印是保护视频版权、提升视频专业性的重要手段之一。以下是六款软件&#xff0c;它们能够帮助你快速进行视频水印制作&#xff0c;让你的视频更具个性和专业性&#xff1a; 1.迅捷视频剪辑软件&#xff1a;…

5月白银现货最新行情走势

美联储5月的议息会议举行在即&#xff0c;但从联邦公开市场委员会&#xff08;FOMC&#xff09;近期透露的信息来看&#xff0c;降息似乎并没有迫切性。——美联储理事鲍曼认为通胀存在"上行风险"&#xff0c;明尼阿波利斯联邦储备银行行长卡什卡利提出了今年不降息的…