工厂模式(Factory Pattern)是面向对象编程中常用的一种设计模式,它属于创建型模式的一种。工厂模式主要用于创建对象,但与直接在代码中使用new
关键字创建对象不同,它通过一个共同的接口来创建对象,从而将对象的创建过程与使用客户端代码分离开来。以下是对工厂模式的详细介绍:
一、工厂模式的主要特点
- 封装对象的创建过程:将对象的创建过程封装在工厂类中,客户端只需要指定需要创建的对象的类型,就可以通过工厂类获得所需的对象,而无需关心对象的具体创建细节。
- 降低耦合度:通过抽象工厂和具体工厂的隔离,降低了客户端与对象之间的耦合度,使得客户端程序更容易扩展和维护。
- 提高程序的可扩展性:当需要新增产品时,只需要添加相应的具体产品类和相应的工厂类即可,无需修改原有代码,符合开闭原则(对扩展开放,对修改关闭),提高了代码的可扩展性。
- 易于维护和升级:因为工厂方法将创建对象的过程集中在一个类中,如果需要修改创建对象的方法,只需要修改相应的工厂类即可,对于客户端来说没有任何影响。
- 代码复用:工厂模式可以将对象的创建过程抽象出来,实现代码复用,增加了代码的灵活性和可重用性。
二、工厂模式的分类
工厂模式主要分为三种类型:简单工厂模式(静态工厂模式)、工厂方法模式和抽象工厂模式
1、简单工厂模式(Static Factory Method)
- 定义一个工厂类,根据传入的不同参数返回不同类的实例。
- 工厂类通常包含多个静态方法,每个方法对应一个具体产品的创建。
- 优点:实现简单,易于理解。
- 缺点:工厂类的职责过重,增加新产品时需要修改工厂类的源代码,违反开闭原则。
简单工厂模式类图
2. 工厂方法模式(Factory Method)
- 定义一个创建对象的接口(抽象工厂),但让子类决定要实例化的类是哪一个。
- 工厂方法让类的实例化延迟到子类中进行。
- 优点:扩展性好,当需要增加新产品时,只需要增加相应的具体产品类和具体工厂类即可。
- 缺点:每增加一个产品,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,增加了系统的复杂度。
工厂方法模式
3.抽象工厂模式(Abstract Factory)
- 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 抽象工厂模式可以看作是多个工厂方法模式的联合使用。
- 优点:可以在类的内部对产品族进行约束,一个具体工厂必须能创建产品族中的所有产品。
- 缺点:增加了系统的抽象性和理解难度,系统的类的个数将大量增加。
抽象工厂模式
三、工厂模式的应用场景
工厂模式在实际开发中有着广泛的应用,如数据库连接、UI控件、文件处理、日志记录、网络通信、消息队列、数据结构、加密解密、消息推送和任务调度等场景。在这些场景中,使用工厂模式可以将对象的创建过程与使用过程分离,提高系统的灵活性和可扩展性。
四、工厂模式例子
1. 简单工厂模式例子
在简单工厂模式中,我们定义一个工厂类,它可以根据传入的参数返回不同类型的实例。
下面是一个使用Java编写的简单工厂模式的示例。我们将创建一个形状工厂,它可以生产圆形、矩形和正方形的实例。首先,我们定义一个形状接口(Shape)和几个实现了该接口的具体类(Circle、Rectangle、Square)。
// 形状接口
interface Shape {
void draw();
}
// 圆形类
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
// 矩形类
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
// 正方形类
class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
接下来,我们定义一个工厂类(ShapeFactory),该类使用静态方法来生成形状对象。
// 形状工厂类
class ShapeFactory {
// 使用 getShape 方法获取形状类型的对象
public static Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
最后,我们可以使用工厂类来获取形状对象,并调用它们的 draw
方法。
public class FactoryPatternDemo {
public static void main(String[] args) {
// 获取 Circle 的对象,并调用它的 draw 方法
Shape shape1 = ShapeFactory.getShape("CIRCLE");
shape1.draw();
// 获取 Rectangle 的对象,并调用它的 draw 方法
Shape shape2 = ShapeFactory.getShape("RECTANGLE");
shape2.draw();
// 获取 Square 的对象,并调用它的 draw 方法
Shape shape3 = ShapeFactory.getShape("SQUARE");
shape3.draw();
}
}
在这个示例中,ShapeFactory
类负责创建 Shape
接口的实例。客户端代码通过传递类型信息(例如字符串)到 ShapeFactory
类的静态方法 getShape
来获取所需形状的实例。这样,客户端与具体类的实现解耦,符合开闭原则,即在不修改客户端代码的情况下,可以扩展新的形状类。然而,简单工厂模式的一个主要缺点是,如果系统需要扩展新的产品族(例如除了形状之外还有颜色等),则需要修改工厂类,这违反了开闭原则的一部分。在这种情况下,可以考虑使用工厂方法模式或抽象工厂模式。
2. 工厂方法模式例子
还是以shape为例,我们利用工程方法进行创建。
首先定义形状接口(Product),并创建三个实现类。
// 形状接口
interface Shape {
void draw();
}
// 圆形类
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
// 矩形类
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
// 正方形类
class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
接下来,定义创建者接口(Creator)和具体创建者(Concrete Creator):
// 创建者接口
interface ShapeFactory {
Shape getShape(String shapeType);
}
// 具体创建者类
class RectangleFactory implements ShapeFactory {
@Override
public Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
}
return null;
}
}
class CircleFactory implements ShapeFactory {
@Override
public Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
}
return null;
}
}
class SquareFactory implements ShapeFactory {
@Override
public Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
最后,使用具体创建者类来获取形状对象,并调用它们的 draw
方法:
public class FactoryMethodPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new CircleFactory();
// 获取 Circle 的对象,并调用它的 draw 方法
Shape shape1 = shapeFactory.getShape("CIRCLE");
shape1.draw();
// 使用 RectangleFactory 来获取 Rectangle 的对象
shapeFactory = new RectangleFactory();
Shape shape2 = shapeFactory.getShape("RECTANGLE");
shape2.draw();
// 使用 SquareFactory 来获取 Square 的对象
shapeFactory = new SquareFactory();
Shape shape3 = shapeFactory.getShape("SQUARE");
shape3.draw();
}
}
在这个示例中,我们为每个形状类创建了一个对应的工厂类(尽管在实际应用中,通常会有一个更通用的工厂类结构,可能通过配置文件或反射来避免为每个产品类编写单独的工厂类)。这有助于演示工厂方法模式的基本原理,即让工厂子类决定要实例化的类是哪一个。然而,对于本例中的简单情况,可能更倾向于使用简单工厂模式或考虑其他设计模式来减少代码重复。
3. 抽象工厂例子
本例子以手机为例,手机相关的抽象产品(如屏幕、电池、操作系统等),并创建具体的产品类来实现这些接口。然后,我们可以定义抽象工厂接口和具体工厂类来生产这些产品。以下是一个简化的例子,展示了如何使用抽象工厂模式来生产不同品牌和型号的手机组件(屏幕和电池):
首先,定义产品的接口及具体的产品:
// 屏幕接口
interface Screen {
void display();
}
// 高端屏幕的实现
class HighEndScreen implements Screen {
@Override
public void display() {
System.out.println("显示高清屏幕");
}
}
// 低端屏幕的实现
class LowEndScreen implements Screen {
@Override
public void display() {
System.out.println("显示普通屏幕");
}
}
// 电池接口
interface Battery {
void charge();
}
// 高效电池的实现
class HighEfficiencyBattery implements Battery {
@Override
public void charge() {
System.out.println("快速充电");
}
}
// 标准电池的实现
class StandardBattery implements Battery {
@Override
public void charge() {
System.out.println("标准充电");
}
}
接下来,定义抽象工厂接口和具体工厂类:
// 手机组件工厂接口
interface PhoneFactory {
Screen createScreen();
Battery createBattery();
}
// 高端手机工厂
class HighEndPhoneFactory implements PhoneFactory {
@Override
public Screen createScreen() {
return new HighEndScreen();
}
@Override
public Battery createBattery() {
return new HighEfficiencyBattery();
}
}
// 低端手机工厂
class LowEndPhoneFactory implements PhoneFactory {
@Override
public Screen createScreen() {
return new LowEndScreen();
}
@Override
public Battery createBattery() {
return new StandardBattery();
}
}
最后,客户端代码,它使用抽象工厂来创建具体的产品对象:
public class PhoneFactoryPatternDemo {
public static void main(String[] args) {
// 使用高端手机工厂
PhoneFactory highEndFactory = new HighEndPhoneFactory();
Screen highEndScreen = highEndFactory.createScreen();
Battery highEndBattery = highEndFactory.createBattery();
highEndScreen.display();
highEndBattery.charge();
// 使用低端手机工厂
PhoneFactory lowEndFactory = new LowEndPhoneFactory();
Screen lowEndScreen = lowEndFactory.createScreen();
Battery lowEndBattery = lowEndFactory.createBattery();
lowEndScreen.display();
lowEndBattery.charge();
}
}
在这个例子中,我们定义了两个手机工厂(高端和低端),每个工厂都能生产特定类型的屏幕和电池。客户端代码通过抽象工厂接口与具体工厂类交互,从而实现了与具体产品类的解耦。这样,如果将来需要添加新的手机类型(例如,中端手机),我们只需要添加新的产品类和对应的工厂类,而无需修改现有的客户端代码。
五、总结
工厂模式是一种非常有用的设计模式,它通过封装对象的创建过程、降低耦合度、提高程序的可扩展性和易于维护性等优点,在软件开发中得到了广泛的应用。然而,它也存在着一些缺点,如工厂类职责过重、系统扩展困难等。因此,在实际应用中需要根据具体场景和需求进行权衡和选择。
如果工厂模式(简单工厂、工厂方法、抽象工厂)对你有用,记得点赞收藏。