什么是设计模式?
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
设计模式总共有 23 种,这些模式可以分为三大类:创建型模式、结构型模式、行为型模式,是从建筑设计领域引入到计算机科学中来的,代表代码设计经验的总结,代码更容易被他人理解,保证代码可靠性、程序的重用性,拓展性更强。
算法不是设计模式,算法致力于解决问题而非设计问题。
设计模式通常描述了一组相互紧密作用的类与对象。
这里引入了类和对象,类是一种用户定义的引用数据类型,也称类类型(结构体)。
对象是类的一种具象。
比如:
struct Animal{
char name[128];
int age;
int sex; //成员属性
void (*peat)();
void (*pdo)(); //成员方法
}
struct Animal dog;
struct Animal cat;
struct Animal person;
什么是简单工厂模式?
工厂模式(Factory Pattern)是最常用的设计模式之一。
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
优点:工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。
缺点:由于工厂类集中了所有实例的创建逻辑,这就直接导致一旦这个工厂出了问题,所有的客户端都会受到牵连;而且由于简单工厂模式的产品室基于一个共同的抽象类或者接口,这样一来,但产品的种类增加的时候,即有不同的产品接口或者抽象类的时候,工厂类就需要判断何时创建何种种类的产品,这就和创建何种种类产品的产品相互混淆在了一起,违背了单一职责,导致系统丧失灵活性和可维护性。而且更重要的是,简单工厂模式违背了“开放封闭原则”,就是违背了“系统对扩展开放,对修改关闭”的原则,因为当我新增加一个产品的时候必须修改工厂类,相应的工厂类就需要重新编译一遍。
总结:简单工厂模式分离产品的创建者和消费者,有利于软件系统结构的优化;但是由于一切逻辑都集中在一个工厂类中,导致了没有很高的内聚性,同时也违背了“开放封闭原则”。另外,简单工厂模式的方法一般都是静态的,而静态工厂方法是无法让子类继承的,因此,简单工厂模式无法形成基于基类的继承树结构。
如图:
示例
#include <stdio.h>
struct Animal{
char name[128];//成员属性
int age;
void (*peat)();//成员方法
void (*pdo)();
};
void dogEat(){
printf("dog eat meat\n");
}
void catEat(){
printf("cat eat fish\n");
}
void personEat(){
printf("person eat food\n");
}
void dogDo(){
printf("dog run\n");
}
void catDo(){
printf("cat run\n");
}
void personDo(){
printf("person run\n");
}
int main(){
struct Animal dog = {
.name = "kate",
.age = 3,
.peat = dogEat,
.pdo = dogDo
};
struct Animal cat = {
.name = "wali",
.age = 6,
.peat = catEat,
.pdo = catDo
};
struct Animal person = {
.name = "lili",
.age = 18,
.peat = personEat,
.pdo = personDo
};//对象
dog.peat();
cat.peat();
person.peat();
dog.pdo();
cat.pdo();
person.pdo();
return 0;
}
这是一个测试demo,在demo里面我们可以看到,所有代码直接写入main,一是我们创建的逻辑全部暴露,安全性不高;二是代码冗杂,可读性不强。尤其是在代码量超级多,且业务逻辑复杂的情况下,劣势尤为明显。
但是如果我们采用简单工厂模式,创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口(API)来指向新创建的对象。
如图:
如上图所示,我们可以直接根据工厂类去创建所需的实例,无需了解这些对象是如何创建以及如何组织的。就本例来说,我们将这些单独的文件放在一起,通过工厂模式产生某种联系,比如链表,此时我们的main负责初始化,调用实例中的函数(实例中加入链表的函数,只有这个函数会暴露在main中)
如图代码:
可以在main中拓展功能。
#include "animal.h"
#include <string.h>
struct Animal* findByName(char *str,struct Animal *phead){
struct Animal *tmp = phead;
if(phead == NULL){
printf("error in link\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 = insertDogList(phead);
phead = insertCatList(phead);
phead = insertPersonList(phead);
while(1){
printf("Input name\n");
scanf("%s",buf);
ptmp = findByName(buf,phead);
if(ptmp != NULL){
ptmp->pdo();
ptmp->peat();
}
memset(buf,'\0',sizeof(buf));
}
}
运行结果如下图: