为什么要使用工厂模式?
当看到“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》设计模式