工厂模式属于创建型模式,通常所说的工厂模式指工厂方法模式,而简单工厂(或者说静态工厂)不属于GoF设计模式。本文从无工厂模式谈起,讲解为何演化出一系列的工厂模式。
一、无工厂模式
假设需要绘制图表,这些图表包括柱状图、折线图、饼状图等,以及将来可能需要扩充的其他类型的图标。一个简单的写法,可以在一个类中用if…else或者switch…case来判断要绘制的图表,然后执行绘制方法。
class Chart {
private String type;
public Chart(String type) {
this.type = type;
}
public void draw() {
if ("histogram".equals(this.type)) {
}
else if ("pie".equals(this.type)) {
}
else if ("line".equals(this.type)) {
}
}
}
显然,这不满足“单一职责”的原则,因为类的使用者和创建者混在一起。为解决这个问题,工厂模式出来了,先看简单工厂。
二、简单工厂
也被称为静态工厂方法模式,它有一个工厂类,提供了一个的静态方法用来产生不同的产品类。
// 产品类接口
public interface Chart {
void draw();
}
// 具体的产品
class PieChart implements Chart {
public PieChart() {
System.out.println("创建饼状图");
}
public void draw() {
System.out.println("绘制饼状图");
}
}
class HistogramChart implements Chart {
public HistogramChart() {
System.out.println("创建柱状图");
}
public void draw() {
System.out.println("绘制柱状图");
}
}
// 工厂类
public class ChartFactory {
public static Chart getChart(String type) {
Chart chart = null;
if (type.equalsIgnoreCase("HistogramChart")) {
chart = new HistogramChart();
}
else if (type.equalsIgnoreCase("PieChart")) {
chart = new PieChart();
}
return chart;
}
}
// 客户类
public class Client {
public static void main(String[] args) {
Chart pieChart = ChartFactory.getChart("PieChart");
pieChart.draw();
System.out.println("----------------");
Chart hChart = ChartFactory.getChart("histogramchart");
hChart.draw();
}
}
/**
运行结果
创建饼状图
绘制饼状图
----------------
创建柱状图
绘制柱状图
**/
简单工厂模式,把产品类的创建逻辑都放在工厂类里面,实现了创建和使用隔离。但是,这还存在一个问题,它不满足“对修改关闭,对扩展开放”的原则。一旦需要增加产品类,就得在工厂类里面添加 if 分支修改工厂的创建逻辑。
为了解决这个问题,工厂方法模式出现了。我们将工厂类进行改造,去掉创建方法的具体实现(一系列的 if…else),让其抽象化。具体的实现则由具体的工程类去完成。
三、工厂方法
// 产品类接口
public interface Drawable {
void draw();
}
// 工厂类接口
public interface IChartFactory {
Drawable createChart();
}
// 具体产品1
public class LineChart implements Drawable {
public LineChart() {
System.out.println("创建折线图");
}
public void draw() {
System.out.println("绘制折线图");
}
}
// 具体产品2
public class PieChart implements Drawable {
public PieChart() {
System.out.println("创建饼状图");
}
public void draw() {
System.out.println("绘制饼状图");
}
}
// 具体工厂1
public class LineChartFactory implements IChartFactory {
public Drawable createChart() {
return new LineChart();
}
}
// 具体工厂2
public class PieChartFactory implements IChartFactory {
public Drawable createChart() {
return new PieChart();
}
}
// 客户类
public class Client {
public static void main(String[] args) {
Drawable chart1 = new LineChartFactory().createChart();
chart1.draw();
System.out.println("----------------");
Drawable chart2 = new PieChartFactory().createChart();
chart2.draw();
}
}
// 运行结果
/**
创建折线图
绘制折线图
----------------
创建饼状图
绘制饼状图
**/
解决了静态工厂方法中存在的需要修改工厂类才能添加新的产品类的缺陷,但是现在又带来另一个问题,每添加一个产品类就得创建一个相应的工厂类,这带来了不少繁琐。如果要创建一系列的产品,比如手机产品,电脑产品,电视产品,同时每类产品下面又有不同的品牌。工厂方法模式遇到这种带有产品层级的问题时要发生类爆炸了。
为了解决这个问题,抽象工厂模式出现了。
四、抽象工厂
// color 产品族接口
public interface Colorful {
void fill();
}
// shape 产品族接口
public interface Drawable {
void draw();
}
/ ***以下是产品族具体类***/
public class Blue implements Colorful {
public void fill() {
System.out.println("用蓝色填充");
}
}
public class Red implements Colorful {
public void fill() {
System.out.println("用红色填充");
}
}
public class LineChart implements Drawable {
public LineChart() {
System.out.println("创建折线图");
}
public void draw() {
System.out.println("绘制折线图");
}
}
public class PieChart implements Drawable {
public PieChart() {
System.out.println("创建饼状图");
}
public void draw() {
System.out.println("绘制饼状图");
}
}
// 抽象工厂类,提供一个产品线的抽象方法
public abstract class AbstractChartFactory {
public abstract Colorful getColor(String color);
public abstract Drawable getChart(String shape);
}
// color产品族工厂类
public class ColorFactory extends AbstractChartFactory {
public Colorful getColor(String color) {
if ("red".equalsIgnoreCase(color))
return new Red();
if ("blue".equalsIgnoreCase(color))
return new Blue();
throw new RuntimeException();
}
public Drawable getChart(String shape) {
return null;
}
}
// shape产品族工厂类
public class ChartFactory extends AbstractChartFactory {
public Colorful getColor(String color) {
return null;
}
public Drawable getChart(String shape) {
if ("line".equalsIgnoreCase(shape))
return new LineChart();
if ("pie".equalsIgnoreCase(shape))
return new PieChart();
throw new RuntimeException();
}
}
// 生产工厂类的工厂类
public class FactoryProducer {
public static AbstractChartFactory getFactory(String choice) {
if (choice.equalsIgnoreCase("shape"))
return new ChartFactory();
if (choice.equalsIgnoreCase("color"))
return new ColorFactory();
throw new RuntimeException();
}
}
// 客户类
public class Client {
public static void main(String[] args) {
AbstractChartFactory shapeFactory = FactoryProducer.getFactory("shape");
Drawable line = shapeFactory.getChart("line");
line.draw();
System.out.println("----------------");
AbstractChartFactory shapeFactory2 = FactoryProducer.getFactory("shape");
Drawable pie = shapeFactory.getChart("pie");
pie.draw();
System.out.println("----------------");
AbstractChartFactory colorFactory = FactoryProducer.getFactory("color");
Colorful red = colorFactory.getColor("red");
red.fill();
System.out.println("----------------");
AbstractChartFactory colorFactory2 = FactoryProducer.getFactory("color");
Colorful blue = colorFactory.getColor("blue");
blue.fill();
}
}
运行结果:
创建折线图
绘制折线图
----------------
创建饼状图
绘制饼状图
----------------
用红色填充
----------------
用蓝色填充
Process finished with exit code 0
其实,我也不知道实际开发中有哪里有用到抽象工厂类,有空了需要去找一下框架代码中的具体例子。
// todo,阅读Spring 源码。
五、参考
- https://www.codeproject.com/articles/716413/factory-method-pattern-vs-abstract-factory-pattern
- https://stackoverflow.com/questions/13029261/design-patterns-factory-vs-factory-method-vs-abstract-factory
- https://www.runoob.com/design-pattern/factory-pattern.html
- https://www.runoob.com/design-pattern/abstract-factory-pattern.html
- 《设计模式 Java版本》 ,作者 进击的皇虫
设计模式系列博文导航
一、创建型 - 5种
原型模式(Prototype Pattern)
抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
工厂模式(Factory Pattern)
单例模式(Singleton Pattern)
助记语:原抽建工单
二、结构型 - 8种
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
适配器模式(Adapter Pattern)
外观模式(Facade Pattern)
过滤器模式(Filter/Criteria Pattern)
桥接模式(Bridge Pattern)
组合模式(Composite Pattern)
装饰器模式(Decorator Pattern)
助记语:想呆室外,过桥组装
三、行为型 - 11种
责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
中介者模式(Mediator Pattern)
迭代器模式(Iterator Pattern)
观察者模式(Observer Pattern)
策略模式(Strategy Pattern)
状态模式(State Pattern)
备忘录模式(Memento Pattern)
模板方法模式(Template Pattern)
访问者模式(Visitor Pattern)
助记语:责令解中谍,观测状被模仿