这是我参与8月更文挑战的第1天,活动详情查看: 8月更文挑战
借 8 月更文挑战来督促自己,感谢掘金!
工厂模式分为三种,分别是简单工厂、工厂方法和抽象工厂,下面分别介绍。
简单工厂
简单工厂模式其实并不是一种设计模式,而是我们的一种编码习惯。下面先看简单工厂模式的 UML 图:
下面来举例说明什么是简单工厂模式。
现在有一个食物这样的接口,关于食物的具体实现有面条和汉堡。有一个食物工厂,是用来生产食物的,根据传入的不同参数生产不同的食物。
食物接口:
/**
* @Author: JonesYong
* @Data: 2021-08-01
* @Description:
*/
public interface Food {
void createFood();
}
面条和汉堡:
/**
* @Author: JonesYong
* @Data: 2021-08-01
* @Description:
*/
public class Noodle implements Food {
@Override
public void createFood() {
System.out.println("noodle was created.");
}
}
/**
* @Author: JonesYong
* @Data: 2021-08-01
* @Description:
*/
public class Hamburger implements Food {
@Override
public void createFood() {
System.out.println("Hamburger was created.");
}
}
下面来看食物工厂:
/**
* @Author: JonesYong
* @Data: 2021-08-01
* @Description:
*/
public class SimpleFactory {
public static Food getFoodInstance(String type) {
Food food = null;
switch (type) {
case "Noodle":
food = new Noodle();
break;
case "Hamburger":
food = new Hamburger();
break;
}
return food;
}
}
像这样,根据传入的不同的参数生产不同的对象,避免无用对象的创建,我们称之为简单工厂模式。但是简单工厂有着很明显的缺点,比如这个时候又多出来一种食物,我们就得去修改食物工厂的代码,这样就违反了开闭原则。
工厂方法
就像上面说的那样,简单工厂模式虽然使用简单,但是确违反了开闭原则。如果使用工厂方法就得到了很好的解决,下面请看工厂方法的 UML:
之前说的简单工厂的模式违反了开闭原则,我们每次增加一种食物,都需要去食物工厂里修改对应的代码!
那么工厂方法又是如何避免这种情况发生的了?仔细看 UML 图可以发现,每一种食物都对应一种食物工厂,如果要新增加一种食物的话,我们需要创建一个工厂出来,用来生产对应的食物。 代码细节如下:
这是一个食物的接口抽象:
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public interface FoodFactory {
Food createFood();
}
具体有两个实现类:
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public class NoodleFactory implements FoodFactory {
@Override
public Food createFood() {
return new Noodle();
}
}
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public class HamburgerFactory implements FoodFactory{
@Override
public Food createFood() {
return new Hamburger();
}
}
想这样,我们需要增加某一个功能的时候,只需要重新定一个具体事物,然后我们客户端再重新增加相对应的工厂就行了。这是不违反开闭原则的,并且解决了客户端和服务的耦合性!
写着写着,好像发现了那你不对劲。思考一下,如果我们每次增加一种食物,就需要增加一个工厂。如果食物越来越多,岂不是额外的工厂类也越来越多,这样就会产生类爆炸的情况!
这个时候抽象工厂出现了,它巧妙地解决了类爆炸的情况。
抽象工厂
先看一下抽象工厂的 UML :
其实抽象工厂挺不好理解的,下面来举一个例子。
现在业务上不仅生产食物,还需要生产饮料。增加了一个饮料接口如下:
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public interface Drink {
void createDrink();
}
它的两个实现类如下:
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public class Milk implements Drink {
@Override
public void createDrink() {
System.out.println("Milk was created.");
}
}
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public class Cola implements Drink {
@Override
public void createDrink() {
System.out.println("Cola was created.");
}
}
结合具体的情景,我们这是一个食品工厂,食品工厂就已经包含食物和饮料了,也不能在
FoodFactory 之外重新创建一个DrinkFactory(公司拒绝搞分裂)。那现在怎么办了?在FoodFactory之内创建一个DrinkFactory也不太合适,毕竟和NoodleFactory 、HamburgerleFactory还是有一定区别的。
那可怎么办呢?我在想,是不是可以把这些个饮料和具体的食物搭配在一起进行出售了?其实这和公司的业务架构有点类似,每个子业务交给独立的大部门完成,这个大部门又可以分成前端、后端、算法,众多的子业务组成了整个公司的业务线。
类比如下:
整个公司的业务相当于FoodFactory,在 FoodFactory下面有许多的大部门(子业务)KFCFactory 、ChinaFactory等,这些个大部门又可以分前端后端啥的(生产不同的食物、饮料)。
代码细节如下:
工厂的接口,每一个食物工厂都需要实现这个接口:
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public interface FoodFactory {
Food createFood();
Drink createDrink();
}
食物工厂有两个实现类,分别用来创建不同的食物:
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public class ChinaFactory implements FoodFactory {
@Override
public Food createFood() {
return new Noodle();
}
@Override
public Drink createDrink() {
return new Milk();
}
}
/**
* @Author: JonesYong
* @Data: 2021-08-02
* @Description:
*/
public class KFCFactory implements FoodFactory {
@Override
public Food createFood() {
return new Hamburger();
}
@Override
public Drink createDrink() {
return new Cola();
}
}
抽象工厂貌似解决了类爆炸的问题,但是仔细想一下还是存在问题的。如果这个时候,我们的需求又增加了,还需要生产冰淇淋,这势必会修改原来的 Factory 对应的功能,违反了开闭原则。
好了,工厂模式的介绍到此结束了。
另外,由于水平有限,有错误的地方在所难免,未免误导他人,欢迎大佬指正!码字不易,感谢大家的点赞关注!🙏