简介:这篇文章的重点呢,不在于如何编写工厂模式的Java代码,而在于"为什么要使用工厂模式"。
有这样一个场景👇
首先有这样一个接口:果汁接口——Juice
,该接口只有一个方法,就是被饮用——void drink();
。现在有2个品牌的果汁,自然,他们都实现了该接口,这两个类分别就是
光明牌果汁——BrightJuice
以及
暗夜牌果汁——DarkJuice
。
那么我们想要喝果汁,肯定是生产出其中一个对象,比如说:
Juice bJuice = new BrightJuice();// 创建一杯光明果汁对象
bJuice.drink();// 喝光明果汁
--------------------------------------------------------
Juice dJuice = new DarkJuice();// 创建一杯暗夜果汁对象
bJuice.drink();// 喝暗夜果汁
但是,果汁的制作并不是这么简单,一杯果汁的诞生,还需要果汁师,水果原料,糖浆,水,色素,秘制配方等。所以,我们创建一杯果汁,就会变成这个样子。
Juice bJuice = new BrightJuice("果汁师Tony","左边第2个桃子","糖浆20g","100ml水","红色色素","秘制配方1");
bJuice.drink();// 喝光明果汁
-----------------------------------------------------------------------------------------------------
Juice dJuice = new DarkJuice("果汁师Jerry","左边第4个菠萝","糖浆30g","100ml水","蓝色色素","秘制配方2");
bJuice.drink();// 喝暗夜果汁
没错,参数很多。而现实世界往往就是这么复杂,也许真的做出一杯果汁,是需要十余种参数的。那么对想要喝果汁的人来说,就很不友好了——创建一杯果汁所要做的事情太多了。于是,为了让果汁的创建和使用(被喝)分离,也为了每次创建果汁时的复杂传参代码可以得到复用,我们需要使用一些技巧,来改进代码的结构。
简单工厂(静态工厂)
没错,就是使用简单工厂。因为new出果汁对象的操作过于繁琐,所以我们专门写一个类,让这个类帮我们去新建果汁对象,而这个类,我们就称它为——果汁工厂
——JuiceFactory
。这个类只有一个方法,也就是说他只干一件事情——就是生产果汁对象。这个方法我们取名为Juice createJuice(String brand);
。
通过该参数命名我们可以看出来,因为有2种牌子的果汁可以生产,所以我们在要求它生产的时候,需要去指定究竟是哪一种:
public class JuiceFactory {
static public Juice createJuice(String brand) {
if(brand == null){
return null;
}
if(brand.equalsIgnoreCase("bright")){
return new BrightJuice("果汁师Tony","左边第2个桃子","糖浆20g","100ml水","红色色素","秘制配方1");
} else if(brand.equalsIgnoreCase("dark")){
return new DarkJuice("果汁师Jerry","左边第4个菠萝","糖浆30g","100ml水","蓝色色素","秘制配方2");
} else {
return null;
}
}
}
可以看出,我们使用这种方式,当我们想喝果汁时候,只需要这样:
Juice bJuice = JuiceFactory.createJuice("bright");
bJuice.drink();// 喝光明果汁
-----------------------------------------------------------------------------------------------------
Juice bJuice = JuiceFactory.createJuice("dark");
bJuice.drink();// 喝暗夜果汁
代码又变成了简单的模样。这
,就是简单工厂的魅力。但是,假如现在又来了一个品牌——黎明牌果汁。那么很明显,我们需要在JuiceFactory
类的createJuice方法里
再添加一个黎明牌的else if
语句。也就是说,我们在添加新的类时,要去修改原来写好的类,这种行为是很不"面向对象"的,也是很不方便的。所以,我们还要对代码进行改进。
工厂
我果汁工厂——JuiceFactory
,之所以会随着新品牌的添加而修改,就是因为还不够抽象。那么我就抽象成一个接口——也就是说,我虽然还是会提供一个创建果汁
——createJuice
的方法,但我不自己去生产了,你们谁想要生产,就来实现我这个接口。这样一来,光明牌喝暗夜牌就分家了,各自建立了工厂 (而不是以前只有一家果汁工厂的方式)。也就是如下的方式:
BrightJuiceFactory implements JuiceFactory
DarkJuiceFactory implements JuiceFactory
LiMingJuiceFactory implements JuiceFactory
//黎明牌果汁工厂
当然,他们各自实现的JuiceFactory接口
的createJuice方法
,自然就是创建各自家品牌的果汁对象。如光明工厂:
public class BrightJuiceFactory implements JuiceFactory, {
@Override
public void createJuice() {
return new BrightJuice("果汁师Tony","左边第2个桃子","糖浆20g","100ml水","红色色素","秘制配方1");
}
}
这样,我们喝果汁的方式就变成了:
Juice bJuice = BrightJuiceFactory实例.createJuice();
bJuice.drink();// 喝光明果汁
-----------------------------------------------------------------------------------------------------
Juice bJuice = DarkJuiceFactory实例.createJuice();
bJuice.drink();// 喝暗夜果汁
实现了对象创建和使用的分离,而且依然得简单明了。同时还解决了新品牌加入时扩展性的问题。顺便一提:简单工厂是使用字符串传参的方式来决定创建哪一个子类对象,这就暗藏着不小心拼错单词的可能,从而得到空的对象,而工厂方法,也很大程度上避免了该隐患的发生(毕竟写出了不存在的工厂类会编译报错的)。
这种结构的搭建,主要解决的问题是——当厂家增多的时候(比如:多了黎明牌这一公司),如何减少代码量的修改以及保证代码的秩序性
(不是专业名词,自己想的描述词,就是让代码看起来是有逻辑的)。
但是,某天,时代变了,社会开始流行一款下午茶组合——一份果汁🍹+小蛋糕🎂
。光明公司和暗夜公司为了抢占市场,也立即推出了光明牌蛋糕和暗夜牌蛋糕。那么把这两种新品加进我们的代码中,很明显,原有代码又要进行修改。所以,我们还需要进一步的改进。
抽象工厂
以光明为例,为了面向接口并满足需求,我们需要新建一个更加抽象的工厂——光明工厂。这里为了更具体,我们就叫他光明下午茶工厂(BrightTeaFactory
)。那么该工厂自然也就不止能生产果汁,还能够生产蛋糕。当然,接口层次也需要做相应的升级,需要添加下午茶工厂
接口。
public interface TeaFactory {//下午茶工厂接口
Juice createJuice();// 生产果汁对象
Cake createCake();// 生产蛋糕对象
}
而那些想要生产下午茶的工厂,同理,自己去实现该接口,然后重写上自己的方法就好了。
需要注意的是,虽然现在工厂升级了,能生产更多的产品(有更多的函数),但在该工厂中的方法里,也并不是直接调用new方法来生产,而是依然使用原来的工厂,比如:
public class BrightTeaFactory implements TeaFactory, {
@Override
public void createJuice() {// 生产光明果汁
return BrightJuiceFactory.creatJuice();
//不使用如下方式直接创建对象
//return new BrightJuice("果汁师Tony","左边第2个桃子","糖浆20g","100ml水","红色色素","秘制配方1");
}
@Override
public void createCake() {// 生产光明蛋糕
return BrightCakeFactory.creatCake();
}
}
所以说,抽象工厂又称为工厂的工厂或超级工厂
在想享用下午茶时,只需要这样(以光明牌为例):
Juice bJuice = BrightTeaFactory实例.createJuice();//得到 BrightJuice对象
Cake bCake = BrightTeaFactory实例.createCake();//得到 BrightCake对象
bJuice.drink();// 喝光明果汁
bCake.eat();// 吃光明蛋糕
这种结构的搭建,主要解决的问题是——在原有逻辑和结构优势的基础上,当产品增多的时候(比如:多了蛋糕这一产品),如何减少代码量的修改以及保证代码的秩序性
。
总结
简单工厂
没有被算在23种设计模式之中,它主要解决了对象创建过于复杂的问题,初步实现了对象创建细节与使用的分离。
工厂
在简单工厂的优势上,又实现了在添加相似厂家时,程序能依然保持"面向对象设计"的相关原则。
抽象工厂
在工厂模式的优势上,又实现了在添加产品时,程序能依然保持"面向对象设计"的相关原则。