简介
- 工厂方法模式是一种创建对象的设计模式
- 定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类
- 符合开闭原则
工厂方法模式包含以下几个主要角色:
- 抽象工厂(Creator) :提供一个创建产品对象的接口,由具体工厂子类实现。
- 具体工厂(Concrete Creator) :实现抽象工厂中的抽象方法,负责创建具体的产品对象。
- 抽象产品(Product) :定义产品的公共接口,所有具体产品类都实现这个接口。
- 具体产品(Concrete Product) :实现抽象产品接口的具体类,代表不同类型的产品对象。
总结
工厂方法模式适用于以下场景:
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
业务
假设我们正在开发一个图形绘制软件,其中有不同类型的图形,如圆形、矩形和三角形。我们可以使用工厂方法模式来创建这些图形对象。
类图
classDiagram
class Shape {
<<interface>>
+draw()
}
class Circle {
+draw()
}
class Rectangle {
+draw()
}
class Triangle {
+draw()
}
class ShapeFactory {
<<Abstract>>
+createShape(): Shape
}
Shape <|.. Circle
Shape <|.. Rectangle
Shape <|.. Triangle
CircleFactory --|> ShapeFactory
RectangleFactory --|> ShapeFactory
TriangleFactory --|> ShapeFactory
Circle <-- CircleFactory
Rectangle <-- RectangleFactory
Triangle <-- TriangleFactory
代码
首先,定义一个图形接口:
public interface Shape {
void draw();
}
然后,实现不同的图形类:
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("绘制圆形");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("绘制矩形");
}
}
public class Triangle implements Shape {
@Override
public void draw() {
System.out.println("绘制三角形");
}
}
接下来,定义一个抽象工厂类:
public abstract class ShapeFactory {
public abstract Shape createShape();
}
然后,实现具体的工厂类:
public class CircleFactory extends ShapeFactory {
@Override
public Shape createShape() {
return new Circle();
}
}
public class RectangleFactory extends ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle();
}
}
public class TriangleFactory extends ShapeFactory {
@Override
public Shape createShape() {
return new Triangle();
}
}
在业务代码中,可以使用工厂方法来创建图形对象:
public class Main {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
Shape circle = circleFactory.createShape();
circle.draw();
ShapeFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.createShape();
rectangle.draw();
ShapeFactory triangleFactory = new TriangleFactory();
Shape triangle = triangleFactory.createShape();
triangle.draw();
}
}
在简单工厂的基础上,加了一层抽象工程,使用里氏替换原则,保证了开闭原则
优点
- 符合开闭原则。如果需要添加新的图形类型,只需要创建一个新的具体图形类和对应的具体工厂类,而不需要修改现有代码。
- 代码结构更加清晰。将图形的创建和使用分离,使得代码的职责更加明确。
缺点
- 增加了系统的复杂性。由于引入了抽象工厂和具体工厂,代码结构相对复杂一些。
在框架中的使用
java
Java 的 JDBC(Java Database Connectivity)中,DriverManager类就使用了工厂方法模式来创建数据库连接。
以下是一个简单的示例代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCTest {
public static void main(String[] args) {
try {
// 使用工厂方法模式创建数据库连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password");
// 使用连接进行数据库操作
//...
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
在这个例子中,DriverManager的getConnection方法就是一个工厂方法,它根据不同的数据库 URL、用户名和密码等参数,创建不同数据库的连接对象。不同的数据库厂商实现了java.sql.Driver接口,这些实现类就相当于具体的工厂,负责创建特定数据库的连接对象。
工厂方法模式在这个场景中的优点:
- 解耦了应用程序和具体的数据库实现。应用程序只需要通过标准的接口来获取数据库连接,而不需要关心具体的数据库实现细节。
- 易于扩展。如果要支持新的数据库,只需要实现
Driver接口,并在应用程序中注册该驱动,就可以通过DriverManager来获取连接,而不需要修改应用程序的核心代码。
spring
例如,在创建 Bean 的过程中,Spring 允许通过自定义的工厂方法来创建对象。假设你有一个复杂的对象创建过程,不想直接在 XML 配置文件中实例化对象,而是通过一个特定的方法来创建。可以这样做:
- 定义一个接口和实现类:
public interface MyService {
void doSomething();
}
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("执行 MyService 的方法。");
}
}
- 创建一个工厂类:
public class MyServiceFactory {
public static MyService createMyService() {
return new MyServiceImpl();
}
}
- 在 Spring 的配置文件中使用工厂方法创建 Bean:
<bean id="myService" factory-method="createMyService" class="com.example.MyServiceFactory"/>
在这个例子中,MyServiceFactory的createMyService方法就是一个工厂方法,Spring 通过调用这个方法来创建MyService的实例。
工厂方法模式在 Spring 中的优点:
- 提供了一种灵活的方式来创建对象,可以处理复杂的对象创建逻辑。
- 可以将对象的创建逻辑封装在工厂类中,使得配置文件更加简洁和易于维护。
- 符合开闭原则,当需要创建新的对象类型时,可以通过添加新的工厂方法来实现,而不需要修改现有的代码。
mybatis
例如,在创建SqlSession对象时,SqlSessionFactory接口定义了创建SqlSession的方法,而不同的SqlSessionFactory实现类(如DefaultSqlSessionFactory)就是具体的工厂,负责创建SqlSession对象。
以下是一个简单的示例代码展示其使用:
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisFactoryMethodExample {
public static void main(String[] args) {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 使用工厂方法创建 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 使用 SqlSession 进行数据库操作
//...
sqlSession.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这个例子中,SqlSessionFactory就像是一个抽象工厂,不同的实现类作为具体工厂,通过openSession()方法这个工厂方法来创建SqlSession对象。
工厂方法模式在这个场景中的优点:
- 解耦了
SqlSession的创建和使用,使用者不需要了解SqlSession的具体创建过程,只需要从工厂获取即可。 - 方便进行扩展和定制,如果需要对
SqlSession的创建过程进行特殊处理,可以通过实现自己的SqlSessionFactory来实现,而不影响现有的代码。
总结
总的来说,工厂方法模式适用于创建对象的逻辑比较复杂,且需要满足开闭原则的场景。