深入解析工厂模式:简单工厂、工厂方法与抽象工厂的区别与应用
一、概述

工厂模式是一个笼统的概念。具体划分的话有三类,分别是简单工厂模式、工厂方法模式和抽象工厂模式。简单工厂模式不属于 23 种设计模式之一,然而它们都属于创建型模式。
二、简单工厂模式
简单工厂模式,也被称作静态工厂模式(Static Factory Method)。之前已经提及,简单工厂模式并不属于 23 种设计模式之列。然而,它属于创建型模式,是工厂模式家族中最为简单且实用的模式,可将其理解为不同工厂模式的一种特殊实现。其 UML 类图如下:
从 UML 图能够得知,首先要有一个接口存在,接着是具体的产品去把这个接口予以实现,之后有一个 Factory 工厂类去生产这些产品。因为该模式并非本文的重点内容,所以仅仅在此处放置一段核心的工厂类代码即可。
public class Factory {
获取汽车的方法是根据传入的汽车类型参数来确定具体的汽车对象。如果传入的汽车类型是轿车类型,就返回一辆轿车对象;如果传入的汽车类型是卡车类型,就返回一辆卡车对象;如果传入的汽车类型是 SUV 类型,就返回一辆 SUV 对象。
switch (carType)
{
case CarType.SportCarType:
return new SportCar();
case CarType.JeepCarType:
return new JeepCar();
如果是 HatchbackCarType 这种车型的情况。
return new HatchbackCar();
default:
引发一个新的异常,该异常的内容为“爱上一匹野马,可我的家里没有草原。你走吧!”;
}
}
}
三、工厂方法模式
工厂方法模式,也被称作多态性工厂模式,它属于设计模式三大分类里的创建型模式。它是抽象工厂模式的孪生兄弟,该模式定义了一个创建对象的接口,然而具体要实例化的类是由子类来决定的,这意味着工厂模式能将实例化工作推迟到子类去进行。
在工厂模式里,核心的工厂类不再承担所有产品的创建工作,而是把具体的创建任务交给子类去完成。这个核心类变成了一个抽象工厂的角色,它仅仅负责给出具体工厂子类必须要实现的接口,却不会去接触到底是哪一个产品应该被实例化这样的细节。
工厂方法模式很符合“开闭原则”。当要增加一个新产品时,只需增加一个具体的产品类以及与之对应的具体工厂。这样就无需关心产品的创建过程,甚至都不需要知晓具体的产品类名称。
他很好地符合了“开闭原则”。然而,每当新增一个新产品时,就需要增加两个类。这样一来,必然会导致系统的复杂度增加。其 UML 结构图如下:
示例:
产品类相关:
//抽象产品类 车
public interface Car {
/**
* 上班函数
*/
void gotowork();
}
//具体产品类 自行车
公共类 Bike 实现了 Car 接口。
@Override
public void gotowork() {
输出“以骑自行车的方式去上班。”。
}
}
//具体产品类 公交车
公共类 Bus 实现了 Car 接口。
@Override
public void gotowork() {
System 显示“坐公交车去上班!”;
}
}
工厂类相关:
//抽象工厂
销毁汽车的方法。
/**
* 获取交通工具
*
* @return
*/
Car getCar();
}
//具体工厂类 生产自行车
公共类 BikeFactory 实现了 ICarFactory 接口。
@Override
public Car getCar() {
return new Bike();
}
}
//具体工厂类 生产公交车
公共类 BusFactory 实现了 ICarFactory 接口。
@Override
public Car getCar() {
return new Bus();
}
}
使用测试:
公共静态的 void 主函数(字符串数组参数 args){
ICarFactory factory = null;
// bike
factory = new BikeFactory();
Car bike = factory.getCar();
bike.gotowork();
// bus
factory = new BusFactory();
Car bus = factory.getCar();
bus.gotowork();
}
输出结果:
骑自行车去上班!
坐公交车去上班!
使用场景:日志记录器;数据库访问等。
四、抽象工厂模式
抽象工厂模式属于创建型设计模式。它提供一个接口,可用于创建相关或依赖对象的家族,且无需明确指定具体类。它允许客户端通过抽象接口创建一组相关产品,无需关心实际产出的具体产品是什么。这样能使客户从具体产品中解耦。
他的优点在于将具体类的生成进行了隔离,这样客户端就无需知晓究竟创建了什么。而其缺点是新增行为会较为麻烦,原因是在添加一个新产品对象时,需要对接口及其下面的所有子类进行更改。其 UML 结构图呈现如下:
具体示例:
形状接口/类
//形状接口
public interface Shape {
void draw();
}
//具体实现类 矩形
类 Rectangle 实现了 Shape 接口。
@Override
public void draw() {
在 Rectangle 的 draw() 方法内部,System 进行了输出操作,输出的内容是 "Inside Rectangle::draw() method." 。
}
}
//具体实现类正方形
公共类 Square 实现了 Shape 接口。
@Override
public void draw() {
System 把 "Inside Square::draw() method." 进行了输出。
}
}
//具体实现类 圆形
类 Circle 实现了 Shape 接口。
@Override
public void draw() {
System 在进行输出,内容为 "Inside Circle::draw() method." 。
}
}
颜色接口/类:
//颜色接口
public interface Color {
void fill();
}
//具体实现类 红色
类 `Red` 实现了 `Color` 接口。
@Override
public void fill() {
System 进行了输出,内容为 "Inside Red::fill() method." 。
}
}
//具体实现类 绿色
公共类 Green 实现了 Color 接口。
@Override
public void fill() {
System 显示了 "Inside Green::fill() method." 。
}
}
//具体实现类 蓝色
类`Blue`实现了`Color`接口。
@Override
public void fill() {
System 打印出了 "Inside Blue::fill() method." 。
}
}
工厂类:
//抽象工厂类
抽象工厂类是一个抽象类。它主要用于定义创建一系列相关或相互依赖对象的接口。这些对象通常属于一个特定的产品系列。通过使用抽象工厂类,可以在不指定具体实现类的情况下创建这些对象的实例。这样可以提高代码的可扩展性和可维护性。在实际应用中,具体的工厂类会实现抽象工厂类中定义的接口,并根据需要创建具体的产品对象。
获取指定颜色的抽象方法,参数为一个字符串类型的颜色,返回值为颜色对象。 这个方法是抽象的,需要在具体的子类中实现。 它用于获取与给定颜色字符串相对应的颜色对象。
公共抽象的 Shape 取得(字符串形状);
}
//形状工厂
公共类 ShapeFactory 继承自 AbstractFactory 类。
@Override
如果 shapeType 为 "CIRCLE",则返回 new Circle();如果 shapeType 为 "RECTANGLE",则返回 new Rectangle();如果 shapeType 为 "TRIANGLE",则返回 new Triangle()。
if(shapeType == null){
return null;
}
如果形状类型等于忽略大小写的“CIRCLE”,那么就执行以下操作;如果形状类型不等于忽略大小写的“CIRCLE”,那么就不执行以下操作。
return new Circle();
如果 shapeType 不区分大小写地等于 "RECTANGLE",那么就执行以下操作;如果 shapeType 不区分大小写地等于 "RECTANGLE",则进行如下处理;若 shapeType 不区分大小写地等于 "RECTANGLE",就会有以下情况;要是 shapeType 不区分大小写地等于 "RECTANGLE",便会执行相应操作;当 shapeType 不区分大小写地等于 "RECTANGLE" 时,就会展开以下步骤;倘若 shapeType 不区分大小写地等于 "RECTANGLE",就会进入相应的处理流程;只要 shapeType 不区分大小写地等于 "RECTANGLE",就会触发相关操作;如果 shapeType 不区分大小写地是 "RECTANGLE",就会执行对应的操作;只要 shapeType 不区分大小写地为 "RECTANGLE",就会进行相关处理;若 shapeType 不区分大小写地属于 "RECTANGLE",就会执行特定操作;当 shapeType 不区分大小写地等同于 "RECTANGLE" 时,就会展开特定步骤;要是 shapeType 不区分大小写地和 "RECTANGLE" 相等,就会执行相应的处理;倘若 shapeType 不区分大小写地与 "RECTANGLE" 一致,就会进行相关操作。
return new Rectangle();
如果 shapeType 不区分大小写等于 "SQUARE",那么
return new Square();
}
return null;
}
@Override
如果传入的字符串 color 为"red",则返回红色;如果传入的字符串 color 为"green",则返回绿色;如果传入的字符串 color 为"blue",则返回蓝色;如果传入的字符串 color 为其他值,则返回 null。
return null;
}
}
//颜色工厂
公共类 ColorFactory 继承自 AbstractFactory 类。
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
public Color getColor(String color) {
if(color == null){
return null;
}
如果颜色等于不区分大小写的“RED”,那么就执行以下操作;如果颜色等于不区分大小写的“RED”,则执行相应的处理;若颜色等于不区分大小写的“RED”,就进行相关的操作;当颜色等于不区分大小写的“RED”时,执行对应的步骤;要是颜色等于不区分大小写的“RED”,就开展相关的工作;假如颜色等于不区分大小写的“RED”,就进行相应的处理流程;只要颜色等于不区分大小写的“RED”,就执行与之对应的动作;倘若颜色等于不区分大小写的“RED”,就开展对应的行动;若颜色等于不区分大小写的“RED”,就执行那相关的操作;当颜色等于不区分大小写的“RED”时,就进行相应的处理事宜;要是颜色等于不区分大小写的“RED”,就开展那相关的工作事宜;假如颜色等于不区分大小写的“RED”,就进行与之对应的处理流程事宜;只要颜色等于不区分大小写的“RED”,就执行那对应的动作事宜。
return new Red();
如果 color 不区分大小写等于“GREEN”,那么
return new Green();
如果 color 不区分大小写等于 "BLUE",那么
return new Blue();
}
return null;
}
工厂生产器:
通过这个类可以方便地获取所需的工厂对象。
公共静态的抽象工厂获取工厂(字符串选择)。如果选择等于“SHAPE”,则返回 ShapeFactory 的新实例。如果选择等于“COLOR”,则返回 ColorFactory 的新实例。如果选择既不等于“SHAPE”也不等于“COLOR”,则返回 null。
如果 choice 不区分大小写等于 "SHAPE",那么
return new ShapeFactory();
如果 choice 不区分大小写等于 "COLOR",那么就执行以下操作。
return new ColorFactory();
}
return null;
}
}
测试类:
公共类 AbstractFactoryPatternDemo 。
public static void main 函数名,其中参数为 String 类型的数组 args 。
//获取形状工厂
AbstractFactory 是一个 shapeFactory,它是由 FactoryProducer 获取到的工厂,并且这个工厂的类型是 "SHAPE"。
//获取形状为 Circle 的对象
Shape 被获取的形状为“CIRCLE”,通过 shapeFactory 获取到的形状是 Shape shape1 。
//调用 Circle 的 draw 方法
shape1.draw();
//获取形状为 Rectangle 的对象
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取形状为 Square 的对象
//调用 Square 的 draw 方法
shape3.draw();
//获取颜色工厂
抽象工厂 colorFactory 是由 FactoryProducer 获取到的工厂,其类型为"COLOR"。
//获取颜色为 Red 的对象
//调用 Red 的 fill 方法
color1.fill();
//获取颜色为 Green 的对象
//调用 Green 的 fill 方法
color2.fill();
//获取颜色为 Blue 的对象
Color color3 是由 colorFactory 获取到的颜色,其颜色名称为“BLUE”。
//调用 Blue 的 fill 方法
color3.fill();
}
}
输出结果:
Inside Circle::draw() method.
在 Rectangle 的 draw() 方法内部。
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.
使用场景:QQ换肤,一套一起换;生成不同操作系统的程序。