1.引子
工厂我们都很熟悉,哪怕对于不会写程序的同学来说,因为我们现实生活中就有很多工厂。你比如说玩具工厂、服饰工厂、五金工厂等。因此对于工厂,我们不需要解释,你都知道它是专门从事生产的,对吧。
同样的,对于写程序的同学来说,工厂模式的含义不言而喻了,它就是用于搞生产的,只不过在程序中我们叫做创建对象。即工厂模式,是一种创建型,用于创建对象的设计模式,其中它又细分为简单工厂、工厂方法、抽象工厂。
另外工厂模式的代码实现比较简单,我通过一个水果商的案例,分别用简单工厂、工厂方法、抽象工厂的方式,实现三个版本案例。期望看完今天的文章后,你能彻底理解工厂设计模式,并在实际项目中去应用它。
2.案例
在具体看代码前,我们先铺垫一下案例背景。生活中有这样的场景,假设我们都喜欢吃水果(其实不用假设,都喜欢吃对吧)。既然有人喜欢吃,就得有人去生产,有需求自然就会有供给,这是生意的本质。
那么我们假设,现在有一家水果商(水果工厂),专门从事生产并向市场供给各种水果,与果汁类产品。我们来看一下这家水果商的发展轨迹,如何一步一步从简单工厂、到工厂方法,最后到抽象工厂,成为一家水果界的巨无霸的。
2.1.简单工厂
2.1.1.背景描述
刚开始创业,小本买卖,品类单一,只卖苹果和梨。不过老板比较有远见,一开始就做好了长远准备,所以我们也配备了类图,更加方便你理解整个设计实现。
2.1.2.类图
2.1.3.代码实现
2.1.3.1.水果接口
/**
* 水果接口
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 9:22
*/
public interface Fruit {
/**
* 吃水果
*/
void eat();
}
2.1.3.2.苹果
/**
* 苹果
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 9:37
*/
public class Apple implements Fruit {
/**
* 吃水果
*/
@Override
public void eat() {
System.out.println("新鲜的苹果,好吃......");
}
}
2.1.3.3.梨
/**
* 梨
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 9:38
*/
public class Pear implements Fruit {
/**
* 吃水果
*/
@Override
public void eat() {
System.out.println("新鲜的梨,好吃......");
}
}
2.1.3.4.水果工厂(简单工厂)
/**
* 工厂设计模式之:简单工厂
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 9:40
*/
public class FruitFactory {
/**
* 简单工厂,生产水果
* 0:生产苹果
* 1:生产梨
* @param fruitType
* @return
*/
public Fruit produce(int fruitType){
if(fruitType == 0){
return new Apple();
}else if(fruitType == 1){
return new Pear();
}else{
// 不支持的水果类型
System.out.println("本店暂时没有对应的水果品类......");
return null;
}
}
}
2.1.3.5.上帝类
/**
* 上帝类,测试执行简单工厂
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 9:43
*/
public class God {
public static void main(String[] args) {
FruitFactory factory = new FruitFactory();
// 吃苹果
Fruit apple = factory.produce(0);
apple.eat();
System.out.println("----------------------------------");
// 吃梨
Fruit pear = factory.produce(1);
pear.eat();
}
}
2.1.3.6.总结分析
通过工厂类FruitFactory中的produce方法,我们可以完成苹果、梨的创建。你看这就是简单工厂设计模式,真的很简单!相信你很容易就能理解了。
那么你能想一想,简单工厂设计模式存在什么问题吗?
我们看到,最主要的是produce方法中的实现逻辑,通过if...else进行条件判断,进而选择生产创建对应的水果,比如0是苹果,1是梨。非常不优雅!主要表现在:
- 如果要创建的水果种类多,会有大量的if...else。代码可读性非常差
- 如果要引进新的水果品类,需要修改produce方法,违反了我们前面分享的设计原则中的开闭原则(对新增开放,对修改关闭)。代码扩展性非常差
基于简单工厂存在可读性、可扩展性的不友好,我们有什么好的解决方法吗?这个时候,工厂方法模式默默的站了起来,并说:我可以。
2.2.工厂方法
2.2.1.背景描述
生意越来越红火,老板喜上眉梢!想要扩充新的品类,比如说卖点桃子什么的。可是突然发现内部管理挺混乱的,引进新品类后,关于水果的摆放啊,账目啊之类的都需要调整。
老板心想,这不行,我们是时候建立一套好的管理体系了,言外之意:引入新的品类,尽量不要影响到原有的品类(开闭原则) 。
2.2.2.类图
2.2.3.代码实现
2.2.3.1.水果工厂(接口或抽象类)
/**
* 工厂方法(水果工厂接口)
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:14
*/
public interface FruitFactory {
/**
* 生产水果
* @return
*/
Fruit produce();
}
2.2.3.2.苹果工厂(工厂方法)
/**
* 工厂方法(苹果工厂实现)
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:16
*/
public class AppleFactory implements FruitFactory{
/**
* 生产水果(苹果)
*
* @return
*/
@Override
public Fruit produce() {
return new Apple();
}
}
2.2.3.3.梨工厂(工厂方法)
/**
* 工厂方法(梨工厂实现)
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:15
*/
public class PearFactory implements FruitFactory {
/**
* 生产水果(梨)
*
* @return
*/
@Override
public Fruit produce() {
return new Pear();
}
}
2.2.3.4.上帝类
/**
* 上帝类,测试执行工厂方法
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:17
*/
public class God {
public static void main(String[] args) {
// 吃苹果
FruitFactory appleFactory = new AppleFactory();
Fruit apple = appleFactory.produce();
apple.eat();
System.out.println("-----------------------------------");
// 吃梨
FruitFactory pearFactory = new PearFactory();
Fruit pear = pearFactory.produce();
pear.eat();
}
}
2.2.3.5.总结分析
通过定义水果工厂FruitFactory接口,以及具体的苹果工厂实现类AppleFactory,梨工厂实现类PearFactory。
- 我们发现在工厂生产方法produce中,不再有if...else条件判断代码,提升了代码的可读性。
- 另外如果需要增加新的品类,比如桃子。我们只需要增加一个桃子工厂实现类PeachFactory即可,原有的苹果工厂、梨工厂都不需要改动。满足开闭原则,提升了代码的可扩展性。
你看这就是工厂方法设计模式,实现也很简单对吧。
那么到这里,你还能再想一想,工厂方法设计模式还有什么问题不能解决吗?
这个时候抽象工厂设计模式,早已安耐不住,大声说:我要登场了!
2.3.抽象工厂
2.3.1.背景描述
水果生意一直都还不错,红红火火。某天老板发现,人们日常生活中不单喜欢吃水果,还喜欢喝果汁。这真是一门好生意!心想我们能不能除了卖水果以外,把卖果汁的生意也做起来呢。
当有了卖果汁的想法以后,老板再次梳理了内部管理体系,发现准备不足。因为我们一直都只准备了卖水果,单从卖水果来说,整套体系运转顺畅,没有任何问题。但是扩充了果汁产品线后,原有的体系又都需要调整了,赚钱真是个头疼的问题!
于是老板找到了咨询公司,咨询公司顾问团队给出建议:上抽象工厂吧!
2.3.2.类图
2.3.3.代码实现
2.3.3.1.水果汁接口
/**
* 水果汁接口
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:47
*/
public interface Juice {
/**
* 喝果汁
*/
void drink();
}
2.3.3.2.苹果汁
/**
* 苹果汁
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:47
*/
public class AppleJuice implements Juice{
/**
* 喝果汁
*/
@Override
public void drink() {
System.out.println("鲜榨的苹果汁,好喝......");
}
}
2.3.3.3.梨汁
/**
* 梨汁
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:48
*/
public class PearJuice implements Juice{
/**
* 喝果汁
*/
@Override
public void drink() {
System.out.println("鲜榨的梨汁,好喝......");
}
}
2.3.3.4.水果工厂(接口或抽象类)
/**
* 抽象工厂(水果,果汁接口)
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:50
*/
public interface FruitFactory {
/**
* 生产水果
* @return
*/
Fruit produceFruit();
/**
* 生产果汁
* @return
*/
Juice produceJuice();
}
2.3.3.5.苹果工厂(抽象工厂)
/**
* 抽象工厂(苹果,苹果汁工厂接口实现类)
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:52
*/
public class AppleFactory implements FruitFactory {
/**
* 生产苹果
*
* @return
*/
@Override
public Fruit produceFruit() {
return new Apple();
}
/**
* 生产苹果汁
*
* @return
*/
@Override
public Juice produceJuice() {
return new AppleJuice();
}
}
2.3.3.6.梨工厂(抽象工厂)
/**
* 抽象工厂(梨,梨汁工厂接口实现类)
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:53
*/
public class PearFactory implements FruitFactory {
/**
* 生产梨
*
* @return
*/
@Override
public Fruit produceFruit() {
return new Pear();
}
/**
* 生产梨汁
*
* @return
*/
@Override
public Juice produceJuice() {
return new PearJuice();
}
}
2.3.3.7.上帝类
/**
* 上帝类,测试执行抽象工厂
*
* @author ThinkPad
* @version 1.0
* @date 2021/2/27 10:54
*/
public class God {
public static void main(String[] args) {
// 吃苹果,和苹果汁
FruitFactory appleFactory = new AppleFactory();
Fruit apple = appleFactory.produceFruit();
apple.eat();
Juice appleJuice = appleFactory.produceJuice();
appleJuice.drink();
}
}
2.3.3.8.总结分析
增加果汁产品线后,我们通过定义FruitFactory接口,在接口中分别有两个方法
- 生产水果:Fruit produceFruit()
- 生产果汁:Juice produceJuice()
实现了多产品线的运作,从代码实现上来说,可以用简单工厂,也可以使用工厂方法,我们的案例使用了工厂方法。
这里你需要注意的是关于抽象工厂设计模式,它是从更大的一个角度看待问题,即一个工厂不单生产单一品类的商品,而是生产多品类商品。简单理解为一个工厂类中,通过多个方法分别生产不同的产品。针对的还是从更大的一个角度,解决满足开闭原则,扩展性的问题。
最后,我们整个工厂设计模式的内容就到这里了。最后一句话简单总结回顾一下。工厂设计模式,是一种创建型的设计模式,它细分类为简单工厂、工厂方法、抽象工厂。你都get到了吗?