最近在学习设计模式,在学了了很多的大佬的分享之后,想写一点自己的理解。主要参考了知乎上一篇文章:参考文章
学习一个新的知识点,都可以先问问自己两个问题,1,没有这个方法将会有什么不好的地方 2,有了这个方法之后会变得怎么更好。带着这两个问题,我们开始学习工厂模式。
首先我们看一下没有工厂模式的时候会怎么样:
那水果举例子,我们要获得苹果,就得知道苹果的制造方法,想要获得香蕉就得知道香蕉的制造方法。如果我们不知道工厂模式,我们会怎么做呢?我们得知道苹果的生产方式和香蕉的生产方式
class user{
Fruit apple = new apple();
apple.grow_up();
apple.pick();
Fruit banana = new banana();
banana.grow_up();
banana.pick();
apple.eat();
banana.eat();
}
这意味这我们必须知道我们想得到水果全部生产过程,这其实是不好的,不利于程序的解耦,比如我们想要改代码,我们得去找出来苹果在哪里,香蕉在哪里。更好的实现方法是创建一个水果工厂类,苹果香蕉都由工厂生产,即便有一万种水果,我们也只要知晓一个水果工厂就行。这个构建封装的过程就是工厂模式。
简单工厂模式:
我们这么做,创建水果工厂:
class FruitFactory{
Fruit create(string name){
if(name == "apple") return new apple();
else if(name == "banana") return new banana();
....
else {
cout << "we don't creat " << endl;
return NULL;
}
}
}
当我们想要使用的时候
FruitFactory my_factory = new FruitFactory;
Fruit apple = my_factory.create("apple");
Fruit banana = my_factory.create("banana");
看代码。我们只需要对接一个水果工厂就行了,相比原来,降低了耦合程度。但是它并不完善,存在一些问题:如果每个水果并不是简单create就行,而是生成一个水果需要很多过程,那么在FruitFactory中我们需要添加很多代码,虽然对于调用者来说,还是简单的代码,但是对于FruitFactory却变成一个大类,一旦要修改或者删除什么,就变得很不容易,修改苹果需要打开这个类,修改香蕉也要打开这个类,不利于解耦。
针对这个问题,我们想到了改进方法,就是创建不同的水果工厂,那么改变苹果就到苹果工厂中改,修改香蕉就到香蕉工厂中改,这就引出了工厂方法模式。
工厂方法模式
还是拿水果举例子
class apple_factory{
Fruit create(){
renturn new apple();
}
}
class banana_factory{
Fruit create(){
renturn new banana();
}
}
...
调用者这么写:
class user{
apple_factory apple_ = new apple_factory();
Fruit my_apple = apple_.create();
banana_factory banana_ = new banana_factory();
Fruit my_banana = banana_.create();
}
这个看起来跟完全不需要设计模式没啥区别啊,都是直接new出来的,有多少种水果就得知道多少工厂,这个耦合度一点也没变低啊。实话就是在代码不多时候确实没啥区别,但是当代码变多,每一个水果生产过程变复杂时候,调用者依然不变,而且想要加入什么水果,直接在user中加入代码就行,不用管具体是怎么生产的。
但是这显然也不是完美的,存在问题,我们可以进一步优化
抽象工厂模式
将工厂的设为基类,让每个水果工厂去继承这个基类。
class Base_factory{
Fruit create();
}
class apple_factory : Base_factory{
Fruit create(){
return new apple();
}
}
class banana_factory : Base_factory{
Fruit create(){
return new banana();
}
}
调用者可以这么写:
class user{
Base_factory apple_f = new apple_factory();
Fruit apple = apple_f.create();
Base_factory banana_f = new banana_factory();
Fruit banana = banana_f.create();
apple.eat();
banana.eat();
}
抽象的好处就是在创建具体的工厂之后,在使用时就无需再关心是哪个工厂类了,使得再替换的时候变得非常容易,我截取原文的一个例子:
是不是特别神奇,一种水果换成另一种水果,只要将第三行改一下就行,其他都不用改。这就是使用继承和多态的好处。
建议看看开头的链接,原文写得十分棒。