工厂模式可以说是我们日常工作过程中使用比较多的一个设计模式了。如果系统比较小,也比较简单,我们可能会直接选择最简单的一种工厂模式即简单工厂模式
例如,我们定义了一个Animal
接口:
interface Animal{
public void printInfo();
}
包含一个 printInfo
方法, 用来自我描述。
然后我们定义两种动物。一种是Cat 另一种是Dog。都实现Animal 接口:
class Cat implements Animal{
@Override
public void printInfo() {
System.out.println("Hello, this is Cat");
}
}
class Dog implements Animal{
@Override
public void printInfo() {
System.out.println("Hello, this is Dog");
}
}
然后为了使用这两个类,同时让上层调用代码在有新的Animal子类出现时尽可能的少做改动。我们应该针对Animal接口编程。然后具体类的创建逻辑放入一个Factory类当中。我们定义为AnimalFactory
class AnimalFactory{
public static Animal getAnimal(String type) {
Animal animal = null;
switch(type) {
case "cat":
animal = new Cat();
break;
case "dog":
animal = new Dog();
break;
}
return animal;
}
}
然后,调用代码会变得比较唯美一点
public static void main(String[] args) {
Animal animal1 = AnimalFactory.getAnimal("cat");
animal1.printInfo();
Animal animal2 = AnimalFactory.getAnimal("dog");
animal2.printInfo();
}
我们看到,我们定义的变量类型是Animal 而不用关注Cat 和Dog 这样的具体实现类的类型了。这就是最最简单的一种工厂模式了。
我们再回过头来看看这个简单工厂模式,我们发现,如果出现的了新的Animal 子类,那么,我们只需要修改AnimalFactory的getAnimal方法,增加switch…case…语句就行了。的确显得很是方便,但是它的缺点也同样明显,就是如果我们在加入一条新的子类的创建逻辑的时候出错了,那么,它的影响的整个AnimalFactory类。也就是说影响到原有的代码也不能正常工作。我们应该不希望这样的事情发生。解决这个问题的方法就是对工厂类做一次抽象,然后为不同的子类增加对应的工厂类。所以我们的工厂类会变成这样
interface AnimalFactory{
public Animal getAnimal();
}
class CatFactory implements AnimalFactory{
@Override
public Animal getAnimal() {
return new Cat();
}
}
class DogFactory implements AnimalFactory{
@Override
public Animal getAnimal() {
return new Dog();
}
}
调用代码就可以变成这样:
AnimalFactory factory = new CatFactory();
Animal animal= factory.getAnimal();
animal.printInfo();
这样我们就解决了当增加Animal子类是会影响到已有代码的问题。因为这样我们就不会再改动到已有的类的创建过程。
然后我们看看在C++中如何实现这两种工厂模式吧,其实我们知道,唯一需要区别的概念就是在C++中没有接口的概念了。接口的话需要用纯虚类的解决。简单工厂模式如下:
class Animal{
public:
virtual void printInfo() = 0;
~Animal(){}
};
class Cat : public Animal{
public:
Cat(){};
void printInfo(){
cout << "this is Cat\n";
}
~Cat(){}
};
class Dog : public Animal{
public:
Dog(){};
void printInfo(){
cout << "this is Dog\n";
}
~Dog(){}
};
class AnimalFactory{
public:
static Animal * getAnimal(const string& type){
Animal * animal = NULL;
if(type == "cat"){
animal = new Cat();
}else if (type == "dog"){
animal = new Dog();
}
return animal;
}
};
int main(int argc, const char * argv[]) {
Animal * animal1 = AnimalFactory::getAnimal("cat");
animal1->printInfo();
Animal *animal2 = AnimalFactory::getAnimal("dog");
animal2->printInfo();
return 0;
}
对应的工厂方法模式如下:
class Animal{
public:
virtual void printInfo() = 0;
virtual ~Animal(){}
};
class Cat : public Animal{
public:
Cat(){};
void printInfo(){
cout << "this is Cat\n";
}
~Cat(){}
};
class Dog : public Animal{
public:
Dog(){};
void printInfo(){
cout << "this is Dog\n";
}
~Dog(){}
};
class AnimalFactory{
public:
virtual Animal * getAnimal() = 0;
};
class CatFactory : public AnimalFactory{
public:
Animal *getAnimal(){
return new Cat();
}
};
class DogFactory : public AnimalFactory{
public:
Animal * getAnimal(){
return new Dog();
}
};
int main(int argc, const char * argv[]) {
AnimalFactory * catfactory = new CatFactory();
AnimalFactory * dogfactory = new DogFactory();
Animal * cat = catfactory->getAnimal();
cat->printInfo();
Animal * dog = dogfactory->getAnimal();
dog->printInfo();
return 0;
}
可以看到,C++的写法和Java基本一致。只是语法上的差别了。
好了下面我们可以看看在C语言里面如何可以很好的实现一个简单工厂模式。
#define CAT 1
#define DOG 2
typedef struct _animal{
char name[32];
void (*printInfo)();
}Animal;
static void printInfo_cat(){
printf("this is Cat\n");
}
static void printInfo_dog(){
printf("this is Dog\n");
}
Animal * getAnimal(int type){
Animal * animal = NULL;
animal = (Animal *)malloc(sizeof(Animal));
assert(animal == NULL);
memset(animal, 0, sizeof(Animal));
switch (type) {
case CAT:
memcpy(animal->name,"cat",3);
animal->printInfo = printInfo_cat;
break;
case DOG:
memcpy(animal->name,"dog",3);
animal->printInfo = printInfo_dog;
break;
}
return animal;
}
这里先给一段很简单明了的代码,其实我们看C语言中的函数指针,我们就知道,它完全提供了一个C++中的虚函数的功能。在C语言中把函数指针指向不同的函数实现就如同C++中虚函数被不同的子类中的特定函数所实现是一样的效果。
当然,如果了解过C++底层对于虚函数的实现我们就知道,这个特性其实就是使用函数指针列表实现的。
好了。到此,利用三种语言去实现工厂模式的一些典型实现基本可以先告一段落。