【C语言】面向对象编程--工厂模式

1、什么是工厂模式?

声明一个结构体,结构体里面的函数已经被定义,将结构体添在链表里面,这就是一个工厂。然后我们可以根据特定的条件,去工厂里面去找对于功能的结构体(遍历链表),找到以后,拿来执行

  • 工厂模式(Factory Pattern)是最常见的设计模式之一。
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的(最佳)方式。
  • 在工厂模式中,他们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的端口来指向新创建的对象。

2、什么是面向对象编程?

 我们可以对比下文程序结构的区别来体会

2.1 实验一_未用使用工厂模式

//OOP.c
#include <stdio.h>
//类:抽象 模板
struct Animal {
  char name[128];
  int age;
  int sex;
  int others;

  void (*peat)();//函数指针,指向函数的指针
  void (*pbeat)();
  void (*test)();//结构体内的元素不一定全都会被用到 
};

//定义函数,后续将传递给结构体中的函数指针 
void dogEat()
{
  printf("狗吃骨头\n");
}
void catEat()
{
  printf("猫吃鱼\n");
}
void personEat()
{
  printf("人吃饭\n");
}
void dogBeat()
{
  printf("咬你小弟弟\n");
}
void catBeat()
{
  printf("抓你小弟弟\n");
}
void personBeat()
{
  printf("猴子偷桃\n");
}

int main()
{
  //以前我们用结构体,喜欢这样用
  struct Animal dog1 = { "小柴",1,1,100,dogEat,dogBeat };
  //name[128];  age; sex; others; (*peat)(); (*pbeat)();(*test)();

  /*
  有时候我们并不想给结构体内所有元素赋值,只给个别赋值,就可以
  */

  //我们可以这样写: 
  struct Animal dog = {
        .peat = dogEat,  //将这个函数的地址给 peat (peat是一个指针)
        .pbeat = dogBeat
  };
  struct Animal cat = {
        .peat = catEat,
        .pbeat = catBeat
  };
  struct Animal person = {
        .peat = personEat,
        .pbeat = personBeat
  };//对象 是事物的具象 

  printf("==============\n");
  dog.peat();//执行 
  cat.peat();
  person.peat();

  dog.pbeat();
  cat.pbeat();
  person.pbeat();
  return 0;
}
2.2 实验二_使用工厂模式

同一个类并列的 功能函数 赋值到一个结构体里的函数指针中,结构体里面的函数已经被定义,将结构体通过头插法 形成链表,这就是一个工厂

 下面用一个导图来直观的描述实验一工厂模式的框架

 

  • 各文件程序
//Animal.h 头文件
#include <stdio.h>
struct Animal {
  char name[128];
  int age;
  int sex;
  int others;

  void (*peat)();//函数指针,指向函数的指针
  void (*pbeat)();
  void (*test)();
  struct Animal* next;
};

struct Animal* putCatInLink(struct Animal* phead);//链接结构体的函数
struct Animal* putDogInLink(struct Animal* phead);
struct Animal* putPersonInLink(struct Animal* phead);
//类1 cat.c
#include <stdio.h>
#include "Animal.h"

void catEat()
{
    printf("猫吃鱼\n");
}

void catBeat()
{
    printf("抓你小弟弟\n");
}

struct Animal cat = {
    .name = "Tom",
    .peat = catEat,
    .pbeat = catBeat
};

struct Animal* putCatInLink(struct Animal *phead) //头插法
{
    if (phead == NULL)
    {
        phead = &cat; //将 结构体cat 的地址传给 指针phead
        return phead;
    }
    else
    {
        cat.next = phead; //cat 的下一个是之前的头
        phead = &cat;     //cat 变成新的头
        return phead;

    }
}
//类2 dog.c
#include <stdio.h>
#include "Animal.h"

void dogEat()
{
    printf("狗吃骨头\n");
}

void dogBeat()
{
    printf("咬你小弟弟\n");
}

struct Animal dog = {
    .name = "xiaohuang",
    .peat = dogEat,
    .pbeat = dogBeat
};

struct Animal* putDogInLink(struct Animal* phead) //头插法
{
    if (phead == NULL)
    {
        phead = &dog;
        return phead;
    }
    else
    {
        dog.next = phead; //dog 的下一个是之前的头
        phead = &dog;     //fog 变成新的头
        return phead;

    }
}

//类3 person.c
#include <stdio.h>
#include "Animal.h"

void personEat()
{
    printf("人吃饭\n");
}

void personBeat()
{
    printf("猴子偷桃\n");
}

struct Animal person = {
    .name = "tp",
    .peat = personEat,
    .pbeat = personBeat
};

struct Animal* putPersonInLink(struct Animal* phead) //头插法
{
    if (phead == NULL)
    {
        phead = &person;
        return phead;
    }
    else
    {
        person.next = phead; //person 的下一个是之前的头
        phead = &person;     //person这个结构体的地址传给phead指针 变成新的头
        return phead;

    }
}
  • 主函数
//main.c
#include "animal.h"
#include <string.h>

struct Animal* findUtilByName(char* str, struct Animal* phead)
{
    struct Animal* tmp = phead;

    if (phead == NULL)
    {
        printf("空\n");
        return NULL;
    }
    else
    {
        while (tmp != NULL)
        {
            if (strcmp(tmp->name, str) == 0)
            {
                return tmp;
            }
            tmp = tmp->next;
        }

        return NULL;
    }
}


int main()
{
    char buf[128] = {'\0'};
    struct Animal *phead = NULL;
    struct Animal* ptmp;

    phead = putCatInLink(phead);//把cat结构体放在了链表里面
    phead = putDogInLink(phead);//把dog结构体放在了链表里面
    phead = putPersonInLink(phead);//把person结构体放在了链表里面

    while (1)
    {
        //根据用户输入的名字,找到相应的结构体
        //根据特定的条件,去工厂里面去找,找到东西以后,拿来执行
        printf("请输入你:Tom、xiaohuang,tp\n");
        scanf_s("%s", buf, sizeof(buf));//注意:VS studio中scanf_s的用法
        ptmp = findUtilByName(buf, phead);
        printf("=========\n");
        if (ptmp != NULL)
        {
            ptmp->pbeat();//点操作符用于直接访问结构体变量的成员,而箭头操作符用于通过指针间接访问结构体变量的成员
            ptmp->peat();
        }
    }
 
    return 0;
}

 

3 总结
大家可以有疑问,怎么实验1中使用了工厂模式后的代码量和文件数比未使用的时候多?这不是增加了阅读代码的复杂度了吗?

如果是针对简单的小项目,确实是这样子的,但是如果是针对几万行的大型项目,利用工厂模式就会显得方便许多;在我们想对项目中的”类“进行增删改查时,我们不用改动main函数中while里面的业务代码,只需要加个类的.c 文件,声名一下,然后在main函数中连接到链表,就完事了,大大的提高程序的维护效率。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值