理解设计模式(二)——工厂方法

理解工厂模式(二)

理解设计模式(一)——简单工厂

写在前面

上一篇我们讲到了简单工厂模式。简单工厂模式其实存在一定的问题(对于C++和Java这样的强类型语言来说),于是我们就要思考改进方案。

简单工厂存在的问题

简单来说,简单工厂存在的问题就是,不满足开闭原则。如果我要添加一个生产的产品,那么我就需要在工厂中添加一次判断,以生产出对应的商品。还是以上一篇中的Logger为例子,如下代码所示:

class Factory {
function create(loggerType) {
if(loggerType == 'file') {
return new FileLogger();
}
if(loggerType == 'db') {
return new DBLogger();
}
// 如果要增加一个日志记录的种类,就需要添加一个if判断
}
}

解决方案

还记得工厂模式本质上是要实现什么吗?

通过修改配置文件,就能改变生成的对象类型。

也就是说,我们给出一个字符串,某个东西就能根据这个字符串返回对应类型的对象。之前简单工厂我们是使用一个函数,根据传入参数进行if判断,给出对应的对象。现在我们其实就是希望能够不使用if,也能进行这样的判断的操作。

想到了吗?(在Java或C#中)我们可以用反射机制。反射机制就是,传入字符串类型的类名,产生对应类型的对象。因此,对于简单工厂的改进如下:

class Factory {
function create() {}
}

class DBLoggerFactory extends Factory {
function create() {
return new DBLogger();
}
}

class FileLoggerFactory extends Factory {
function create() {
return new FileLogger();
}
}

// 读取配置文件
let config = readConfig();
// 使用反射机制产生对应的工厂
let facotry = Reflection(config.factoryName);
let product = factory.create();

现在的代码是不是就满足开闭原则了呢?我们想要添加一个新的Logger,只需要新增一个LoggerFactory,并修改配置文件即可。

Javascript需要工厂方法吗?

看过上一篇肯定就知道,当然是不需要的啦。之所以会有上面这样的代码,其实是写给强类型语言看的啦。FileLoggerFactoryDBLoggerFactory 之所以需要继承Factory,是因为后面期望能把这两个工厂类的对象赋值给同一个变量。所以,我们需要一个Factory类,来定义这个变量。这样,DBLoggerFactory和FileLoggerFactory就都可以赋值给Factory类的变量了。但是对于弱类型的语言来说,这样做就是多此一举了。对于弱类型的语言,完全可以像下面这样写:

class DBLoggerFactory {
function create() {
return new DBLogger();
}
}

class FileLoggerFactory {
function create() {
return new FileLogger();
}
}

// 读取配置文件
let config = readConfig();
// 使用反射机制产生对应的工厂
let facotry = Reflection(config.factoryName);
let product = factory.create();

对于Javascript而言,这样写还是啰嗦了。最简单的方法,上面一篇已经介绍过啦,这就不再继续介绍啦。

写在最后

好了,我们还剩最后一个工厂模式没有讲——抽象工厂模式。也就是说,现在的工厂方法模式必然还是存在一定的问题,让抽象工厂模式来解决。可以先想想是什么样的问题。😄

Author: LeoB_O
Link: https://leob-o.github.io/2019/04/24/FactoryPattern2/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.