理解工厂模式(一)
写在前面
最近在上设计模式这门课,吐槽一下某人教的实在是,听不懂(不过比上学期教的好多了,值得鼓励一下)。于是自己上网搜索资料,然后看书,稍微有点体会。
说了点废话,下面开始。
为什么要用工厂模式
显然,要用工厂模式是因为我们遇到了一些问题。那么我们到底遇到了什么问题,才要使用工厂模式呢?下面直接用伪代码举个例子来说明一下。
// BlaBlaBla 假设这里是一些其他的代码 |
这段代码假设了这样一个场景,我们需要在一个程序中的多个不同的地方使用Logger,用来记录日志。这里我们使用了FileLogger。
这段代码有什么问题?某人大概会说,没有面向抽象编程,而是面向了具体编程。
啥玩意儿,说人话。
举例来说,如果我们要把日志记录到标准I/O流里面,而不是File里面,我们需要如何修改程序?把代码里面所有的FileLogger替换成IOLogger?这样做,我们需要把分散在代码当中各处的FileLogger一个一个找出来,然后替换,实在是有点麻烦。
还有,如果我们要允许用户自己选择使用哪种Logger,现在这样的代码结构只能使用if…else进行判断,如果要增加一种情况,就要增加一个if…具体如下所示:
if(userChoose == 'file') { |
这是完全无法接受的。
解决方案
那么我们如何解决这个问题呢?简单工厂模式就是来做这个事情的。下面直接用代码举例子:
class Factory { |
等等!是不是感觉和直接new没有什么区别?甚至还多此一举加了一个Factory,白白增加代码量?是的,这就是很多例子的问题。这样子并没有发挥简单工厂模式的作用。
回到那个让用户自己选择Logger类型的例子,真正使用简单工厂模式应该是这样的:
class Factory { |
现在再想想,用户如果要替换另一个类型的Logger,是不是只要修改配置文件就可以了?不用在代码中到处找散落在各处的new语句了?
也就是说,我们增强了代码的稳定性,通俗点说,就是不用到处改代码,只要改配置文件。本质上来说,这就是增加了代码的内聚。也就是把原本散落在各处的new语句聚集到了一起。
思考
那么,我们就必须要声明一个Factory类来做这个事情吗?或者说,我们必须要使用面向对象的思想来解决这个问题吗?其实不是的。
想一想,我们最根本的目的是什么?是为了实现能只修改一个地方,就能修改整个代码中多个地方创建的对象的类型。这也就是所谓的对象懒创建(Lazy create)。意思是,等到我运行到创建的那一行语句的时候,再决定创建什么对象。而new语句是在编译的时候就决定了创建什么对象。
用例子来说明,new LoggerFile()
和factory.create(config.type)
的区别就是,new语句从一开始就决定了我要创建一个LoggerFile类型的对象,而factory等到运行到这一行时,才根据config.type的值来决定创建什么类型的对象。这就是Lazy的地方。
好了,有点扯出去了。下面给出Javascript不使用面向对象,解决我们上面提到的问题的代码:
// 读取config |
这里,没有用到面向对象,同样解决了上面的问题。当然这有Javascript语言特性的原因在里面。而且我可以说,这样的代码的优越性是要高于之前面向对象的代码的。
之前面向对象的代码,我们如果要新增一种Logger类型,就要在工厂中新加一个if语句。而我现在给出的代码,不需要对已有代码进行修改,只需要在后面添加就行。如果你愿意,也可以把新添加的代码单独开一个文件。这部分如何实现可以自己思考一下。
总结
简单工厂就是为了解决这样一个问题:如果要修改创建的对象的类型,就要在整个程序中修改所有的new语句。使用了简单工厂就可以实现改变一个地方,就能改变整个程序中创建的所有对象的类型。
当然这个方法还是有问题。就像上面说的,如果你非得用面向对象的方法,你现在要在工厂里新增加一个Logger类型,就得增加一个if语句。
谁来解决这个问题呢?麻烦的工厂方法模式可以解决这个问题。但是我真的不喜欢,太麻烦了。但是,要上课,要考试鸭。现在这里挖个坑,下一篇就来讲讲工厂方法模式吧。
JS天下第一。
希望某些人能提高一下自己的职业技能,业务能力。