c语言与设计模式(2)——简单工厂模式

为什么要使用工厂模式?

当看到“new”,就想到“具体”。因为“new”的右值总是一个实例。有了具体实例就违法了针对接口编程的原则了。在技术上,new没有错,错在“产品经理”们,错在改变。

针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。为什么呢?如果代码针对接口而写,那么通过多态,它可以与任何新类实现该接口。当代码使用大量的具体类是,等于是自找麻烦,因为一旦加入新的具体类,就必须改变代码。也就是说,你的代码并非“对修改关闭”。

所以该怎么办?当遇到这样的问题是,就应该回到OO设计原则去寻找线索——“找出会变化的方面,把它们从不变的部分分离出来”

-------------------------以上99%摘自《head first》设计模式----------------------------

 

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。

简单工厂模式不属于Gof 23的一种,但是它和抽象工厂和工厂方法一样,经常被用于封装创建对象的代码

在使用简单工厂模式时,首先需要对产品类进行重构,不能设计一个包罗万象的产品类,而需根据实际情况设计一个产品层次结构,将所有产品类公共的代码移至抽象产品类,并在抽象产品类中声明一些抽象方法,以供不同的具体产品类来实现

 

我们以制作pizza为例子,当然很懒的我省略了某些步骤,做出来的肯定不好吃 : )

/*product_pizza.h 这里就是抽象出来了不变的部分*/
#ifndef __PRODUCT_PIZZA_H__
#define __PRODUCT_PIZZA_H__

struct product_pizza {
    void (*prepare)(struct product_pizza *product);
    void (*bake)(struct product_pizza *product);
    void (*box)(struct product_pizza *product);
};

extern struct product_pizza *order_pizza(char *type);

#endif

/*cheese_pizza.h “继承”抽象产品类,并加入变化的部分*/

#ifndef __CHEESE_PIZZA_H__
#define __CHEESE_PIZZA_H__

#include "product_pizza.h"

struct cheese_pizza {
    struct product_pizza product;
    char *name;
};

struct cheese_pizza *create_cheese_pizza();

#endif

/*chees_pizza.c 实现具体类*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "cheese_pizza.h"

#define MAX_NAME_LEN 23

static void cheese_pizza_prepare(struct product_pizza *product)
{
    struct cheese_pizza *cheese = (struct cheese_pizza *)product;

    printf("%s prepare\n", cheese->name);
}

static void cheese_pizza_bake(struct product_pizza *product)
{
    struct cheese_pizza *cheese = (struct cheese_pizza *)product;
    printf("%s bake\n", cheese->name);
}

static void cheese_pizza_box(struct product_pizza *product)
{
    struct cheese_pizza *cheese = (struct cheese_pizza *)product;
    printf("%s box\n", cheese->name);
}


int cheese_pizza_initialise(struct cheese_pizza *cheese, char *name)
{
    int name_len = strlen(name);
    if (name_len > MAX_NAME_LEN) {
        printf("name len is too long, truncate it: %d\n", name_len);
        name_len = MAX_NAME_LEN - 1;
        name[name_len] = 0;
    }
    cheese->name = calloc(1, name_len + 1);
    assert(cheese->name != NULL);
    strcpy(cheese->name, name);
    cheese->product.prepare = cheese_pizza_prepare;
    cheese->product.bake = cheese_pizza_bake;
    cheese->product.box = cheese_pizza_box;

    return 0;
}

struct cheese_pizza *create_cheese_pizza(char *name)
{
    struct cheese_pizza *cheese = calloc(1, sizeof(struct cheese_pizza));
    if (cheese) {
        cheese_pizza_initialise(cheese, name);
    }
    return cheese;
}

/*同上道理,我们实现clam pizza实例*/

/*clam_pizza.h*/
#ifndef __CLAM_PIZZA_H__
#define __CLAM_PIZZA_H__

#include "product_pizza.h"

struct clam_pizza {
    struct product_pizza product;
    char c; //变化的部分
};

extern struct clam_pizza *create_clam_pizza(char c);

#endif


/*clam_pizza.c*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "clam_pizza.h"

static void clam_pizza_prepare(struct product_pizza *pizza)
{
    struct clam_pizza *clam = (struct clam_pizza *)pizza;
    printf("clam prepare %c\n", clam->c);
}

static void clam_pizza_bake(struct product_pizza *pizza)
{
    struct clam_pizza *clam = (struct clam_pizza *)pizza;
    printf("clam bake %c\n", clam->c);
}

static void clam_pizza_box(struct product_pizza *pizza)
{
    struct clam_pizza *clam = (struct clam_pizza *)pizza;
    printf("clam box %c\n", clam->c);
}

int clam_pizza_initialise(struct clam_pizza *clam, char c)
{
    clam->c = c;
    clam->product.prepare = clam_pizza_prepare;
    clam->product.bake = clam_pizza_bake;
    clam->product.box = clam_pizza_box;
    
    return 0;
}

struct clam_pizza *create_clam_pizza(char c)
{
    struct clam_pizza *clam = calloc(1, sizeof(struct clam_pizza));
    if (clam) {
        clam_pizza_initialise(clam, c);
    }
    return clam;
}

/*product_pizza_factory.c*/

#include <stdio.h>
#include <string.h>
#include "cheese_pizza.h"
#include "clam_pizza.h"

/*根据参数创建不同种类的pizza,注意返回值为“抽象类(或者叫接口)”,这样客户调用的时候无需关系是那个具体的类,直接操作即可*/
struct product_pizza *create_pizza(char *type)
{
    struct product_pizza *pizza = NULL;
    
    if (!strcmp(type, "cheese")) {
        printf("create cheese\n");
        pizza = (struct product_pizza *)create_cheese_pizza("cheese");
    } else if (!strcmp(type, "clam")) {
        printf("create clam\n");
        pizza = (struct product_pizza *)create_clam_pizza('c');
    } else {
        printf("haven't support this type\n");
    }

    return pizza;
}

/*我们无需知道具体的类,直接操作接口即可*/
struct product_pizza *order_pizza(char *type)
{
    struct product_pizza *pizza = create_pizza(type);
   
    if (pizza) {
        pizza->prepare(pizza);
        pizza->bake(pizza);
        pizza->box(pizza);
    }
    return pizza;
}
#include <stdio.h>
#include "product_pizza.h"

int main(void)
{
    order_pizza("clam");
    order_pizza("cheese");
    order_pizza("others");

    return 0;
}

 

参考链接 https://blog.csdn.net/lovelion/article/details/9300549

《Head First》设计模式

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值