工厂模式也是一种常见的创建类模式,参考了网上的众多博文,本篇博文我们系统地来分析一下什么是工厂模式,为什么要采用工厂模式,以及工厂模式的发展优化。
工厂模式的发展有以下的三个阶段:
- 简单工厂模式
- 方法工厂模式
- 抽象工厂模式
简单工厂模式:
我们在日常开发中,为了使系统更加符合“单一职责原则”,我们通常将对象的创建和使用分离,这样有利于对系统功能的复用和系统的维护。因此,提出了简单工厂模式这一概念。用户负责调用,即所谓的使用功能,而新建一个工厂对象,负责对象的创建工作,对象的创建细节都隐藏在工厂类中,用户无需知道创建细节。
下面我们通过一个实例来说明简单工厂模式。
有一个鞋子销售商,他负责卖Nike的运动鞋,休闲鞋和工作鞋。自然生产鞋子的工作交给工厂来做,销售商并不需要知道生产鞋子的细节,包括尺寸外观等等特征,而此处为了简便统统不表示。
此时整个系统的类图如下所示:
代码实现如下:
public interface Shoes {
public void sale();
}
public class AthleticsShoes implements Shoes {
@Override
public void sale() {
System.out.println("销售了一双运动鞋");
}
}
public class CasualShoes implements Shoes{
@Override
public void sale() {
System.out.println("销售了一双休闲鞋");
}
}
public class WorkShoes implements Shoes{
@Override
public void sale() {
System.out.println("销售了一双工作鞋");
}
}
public class ShoesFactory {
public Shoes produceShoes(String type){
if (type == null){
System.out.println("不存在该鞋子类型");
return null;
}
switch (type){
case "AthleticsShoes":
return new AthleticsShoes();
case "CasualShoes":
return new CasualShoes();
case "WorkShoes":
return new WorkShoes();
default:
System.out.println("不存在该鞋子类型");
return null;
}
}
}
public class Saler {
public static void main(String args[]){
ShoesFactory factory = new ShoesFactory();
Shoes shoes1 = factory.produceShoes("AthleticsShoes");
Shoes shoes2 = factory.produceShoes("CasualShoes");
Shoes shoes3 = factory.produceShoes("WorkShoes");
shoes1.sale();
shoes2.sale();
shoes3.sale();
}
}
方法工厂模式:
上面介绍了简单工厂模式,已经能够将对象的创建和使用分开。我们再来思考一下当前可能出现的问题,如果随着用户需求的变化,销售商需要卖登山鞋。在简单工厂模式下,我们需要怎么做呢?
首先,我们要新建一个登山鞋的类并实现Shoes接口,接着我们要在工厂类中修改produceShoes方法,这显然违反了“开闭原则”。因此,在简单工厂模式的思路上,提出了方法工厂模式。所谓方法工厂模式,就是进一步将工厂对象抽象,之后每新实现一个工厂类即可。
还是上面的实例,此时整个系统的类图如下:
代码实现如下:
public interface Shoes {
public void sale();
}
public class AthleticsShoes implements Shoes {
@Override
public void sale() {
System.out.println("销售了一双运动鞋");
}
}
public class CasualShoes implements Shoes {
@Override
public void sale() {
System.out.println("销售了一双休闲鞋");
}
}
public class WorkShoes implements Shoes {
@Override
public void sale() {
System.out.println("销售了一双工作鞋");
}
}
public interface ShoesFactory {
public Shoes produceShoes();
}
public class AthleticsShoesFactory implements ShoesFactory {
@Override
public Shoes produceShoes() {
return new AthleticsShoes();
}
}
public class CasualShoesFactory implements ShoesFactory {
@Override
public Shoes produceShoes() {
return new CasualShoes();
}
}
public class WorkShoesFactory implements ShoesFactory {
@Override
public Shoes produceShoes() {
return new WorkShoes();
}
}
public class Saler {
public static void main(String args[]){
AthleticsShoesFactory factory1 = new AthleticsShoesFactory();
CasualShoesFactory factory2 = new CasualShoesFactory();
WorkShoesFactory factory3 = new WorkShoesFactory();
Shoes shoes1 = factory1.produceShoes();
Shoes shoes2 = factory2.produceShoes();
Shoes shoes3 = factory3.produceShoes();
shoes1.sale();
shoes2.sale();
shoes3.sale();
}
}
抽象工厂模式:
经过上面的优化后,如果添加了新的鞋子,我们能通过新建一个鞋子类和一个工厂类来实现,这样既能够将对象创建和使用分离,同时还没有违背“开闭原则”。
这时,又有一个新的问题出现了,按照方法工厂模式的思路,当生产的产品很多时,那么相应的工厂类也有很多,整个系统就会变得庞大而难以管理,增加系统开销,怎么处理这个问题呢。于是便有了抽象工厂模式。
抽象工厂就是将工厂对象进一步抽象,我们还是通过上面的实例来说明。现在假设我们要考虑鞋子的颜色属性,分别有红色和蓝色两种颜色。所以现在分别有六种不同的鞋子,按照方法工厂的思路我们要生成六个相对应的工厂类,显然这项工作是不合理的。
我们现在来想办法看看如何改善这个情况,定义同一颜色的鞋子为一个族,之后我们就通过实现对族的扩展来实现生产更多种类的鞋子,同时工厂类的个数也不多,这是如何实现的呢。我们还是看代码。
public interface Shoes {
public void sale();
}
public abstract class AthleticsShoes implements Shoes {
public abstract void sale();
}
public abstract class CasualShoes implements Shoes {
public abstract void sale();
}
public abstract class WorkShoes implements Shoes {
public abstract void sale();
}
public class BlueAthleticsShoes extends AthleticsShoes {
@Override
public void sale() {
System.out.println("销售了一双蓝色的运动鞋 ");
}
}
public class BlueCasualShoes extends CasualShoes {
@Override
public void sale() {
System.out.println("销售了一双蓝色的休闲鞋");
}
}
public class BlueWorkShoes extends WorkShoes {
@Override
public void sale() {
System.out.println("销售了一双蓝色的工作鞋");
}
}
public class RedAthleticsShoes extends AthleticsShoes {
@Override
public void sale() {
System.out.println("销售了一双红色的运动鞋");
}
}
public class RedCasualShoes extends CasualShoes {
@Override
public void sale() {
System.out.println("销售了一双红色的休闲鞋");
}
}
public class RedWorkShoes extends WorkShoes {
@Override
public void sale() {
System.out.println("销售了一双红色的工作鞋");
}
}
public interface ShoesFactory {
public AthleticsShoes produceAthleticsShoes();
public CasualShoes produceCasualShoes();
public WorkShoes produceWorkShoes();
}
public class BlueShoesFactory implements ShoesFactory {
@Override
public AthleticsShoes produceAthleticsShoes() {
return new BlueAthleticsShoes();
}
@Override
public CasualShoes produceCasualShoes() {
return new BlueCasualShoes();
}
@Override
public WorkShoes produceWorkShoes() {
return new BlueWorkShoes();
}
}
public class RedShoesFactory implements ShoesFactory {
@Override
public AthleticsShoes produceAthleticsShoes() {
return new RedAthleticsShoes();
}
@Override
public CasualShoes produceCasualShoes() {
return new RedCasualShoes();
}
@Override
public WorkShoes produceWorkShoes() {
return new RedWorkShoes();
}
}
public class Saler {
public static void main(String args[]) {
RedShoesFactory factory1 = new RedShoesFactory();
BlueShoesFactory factory2 = new BlueShoesFactory();
Shoes shoes1 = factory1.produceAthleticsShoes();
Shoes shoes2 = factory1.produceCasualShoes();
Shoes shoes3 = factory1.produceWorkShoes();
Shoes shoes4 = factory2.produceAthleticsShoes();
Shoes shoes5 = factory2.produceCasualShoes();
Shoes shoes6 = factory2.produceWorkShoes();
shoes1.sale();
shoes2.sale();
shoes3.sale();
shoes4.sale();
shoes5.sale();
shoes6.sale();
}
}
在抽象工厂模式想,加入我们随着用户需求变化新添加了一种鞋子颜色,我们只需新建三个新颜色的鞋子类和一个新颜色的工厂类,而不需要像方法工厂模式一样需要添加三个工厂了,因此抽象工厂模式在方法工厂模式上做了进一步的优化。
是不是抽象工厂模式就是万能了呢?答案当然是否定的。如果我们随着用户需求的变化,需要生产马丁靴怎么办?我们还需要去修改抽象工厂中的方法,破坏了开闭原则。所以在实现具体问题时,一开始就要确定好需求分析。
感悟:
在学习工厂模式的时候,在这里卡了好几天。时间花在哪里了呢,一方面是自己的理解能力不够强,理解得比较慢,而另一方面,我发现网上的各种博客中有很多的博客根本没有讲清楚工厂模式,有的甚至混淆了方法工厂模式和抽象工厂模式的概念。当然,我也是如此,这篇博文中或多或少会有一些我没有彻底明白的地方,可能是我理解的深度不够或者是理解错了。所以交流就显得特别重要,如果大家能看到我这篇博文,觉得有什么不合理的地方,请不吝赐教,多多交流互相进步。菜鸟也能快速的成长。