用静态工厂方法来代替构造方法。
public class Student {
private String name;
private int age;
private String studentId;
private Student(String name, int age, String studentId) {
this.name = name;
this.age = age;
this.studentId = studentId;
}
public static Student createStudent(String name, int age, String studentId) {
// 在静态工厂方法中执行一些额外的逻辑
// 例如参数验证、生成默认的学生ID等
// 调用私有构造器创建学生对象
return new Student(name, age, studentId);
}
// Getter 和 Setter 方法...
}
静态工厂方法相较于构造方法的五个优点:
- 有自己的名称,而构造方法必须与类名一致。
- 不用每次被调用时都会创建一个新的对象,它可以返回预先构造好的对象。
- 可以返回所声明的返回类型的任何子类型的对象。
- 所返回对象的类可以输入的参数不同而改变。
- 在编写包含该方法的类时,所返回对象的类并不一定存在。
缺点:
- 如果没有共有的或者受保护的构造方法,就无法为这些类创建子类。(因祸得福)
- 在API文档中可能会很难发现这个方法。(无伤大雅)
下面来详细谈一谈每一个优缺点:
优点一:
静态工厂方法有自己的名称,而构造方法必须与类名一致:
import java.time.LocalDate;
public class DateUtils {
private DateUtils() {
// 私有构造方法,防止实例化
}
public static LocalDate createToday() {
// 创建表示当前日期的对象
return LocalDate.now();
}
public static LocalDate createDate(int year, int month, int day) {
// 创建指定年月日的日期对象
return LocalDate.of(year, month, day);
}
}
优点二:
静态工厂方法不用每次被调用时都会创建一个新的对象,它可以返回预先构造好的对象:
// 饿汉模式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
// 私有构造函数
}
public static Singleton getInstance() {
return instance;
}
// 其他方法...
}
// 懒汉模式
public class Singleton {
private static Singleton instance;
private Singleton() {
// 私有构造函数
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// 其他方法...
}
优点三:
静态工厂方法可以返回所声明的返回类型的任何子类型的对象:
举个例子:createShape静态工厂方法声明的返回值类型是Shape,但它却可以返回Shape的子类型Circle和Square。
public class Shape {
private String name;
private Shape(String name) {
this.name = name;
}
public String getName() {
return name;
}
public static Shape createShape(String name) {
if (name.equalsIgnoreCase("circle")) {
return new Circle();
} else if (name.equalsIgnoreCase("square")) {
return new Square();
} else {
return new Shape(name);
}
}
}
public class Circle extends Shape {
public Circle() {
super("Circle");
}
}
public class Square extends Shape {
public Square() {
super("Square");
}
}
优点四:
静态工厂方法所返回对象的类可以输入的参数不同而改变:
优点五:
静态工厂方法在编写包含该方法的类时,所返回对象的类并不一定存在:
在JDBC(Java数据库连接)中的服务提供者框架是一个典型的例子,其中静态工厂方法可以返回对象的类在编写包含该方法的类时并不一定存在。
在JDBC中,服务提供者框架用于加载和管理数据库驱动程序。驱动程序供应商可以通过实现特定接口并提供驱动程序的实现来注册其驱动程序。服务提供者框架允许应用程序通过静态工厂方法获取适当的驱动程序实例,而无需显式引用特定的驱动程序类。
下面是一个简化的示例,展示了JDBC服务提供者框架的代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCProviderFramework {
// 私有构造函数,防止实例化
private JDBCProviderFramework() {
}
// 静态工厂方法,返回数据库连接对象
public static Connection getConnection(String url, String username, String password) throws SQLException {
// 加载并注册合适的数据库驱动程序
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new SQLException("Failed to load database driver");
}
// 获取数据库连接
return DriverManager.getConnection(url, username, password);
}
}
public class Main {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/mydb";
String username = "root";
String password = "password";
try {
Connection connection = JDBCProviderFramework.getConnection(url, username, password);
// 使用数据库连接执行操作
// ...
} catch (SQLException e) {
e.printStackTrace();
}
}
}
在上述示例中,JDBCProviderFramework
类是服务提供者框架的一部分。它包含一个私有构造函数和一个静态工厂方法 getConnection()
,用于获取数据库连接对象。
在 getConnection()
方法中,首先使用 Class.forName()
方法加载并注册合适的数据库驱动程序,这里以MySQL驱动程序为例。然后,通过 DriverManager.getConnection()
方法获取数据库连接对象,并将其返回。
在 Main
类的 main()
方法中,我们使用 JDBCProviderFramework.getConnection()
方法获取数据库连接对象,并在实际应用程序中使用该连接对象执行数据库操作。
这里的关键是,在编写 JDBCProviderFramework
类时,并没有显式引用或依赖于特定的数据库驱动程序类。相反,通过使用服务提供者框架和静态工厂方法,可以在未来动态加载和使用不同的数据库驱动程序,而无需修改 JDBCProviderFramework
类的代码。
这种设计允许在未来定义或扩展返回的对象类(即不同的数据库驱动程序),以适应新的数据库技术或供应商。通过配置和动态加载,应用程序可以灵活地选择和切换不同的数据库驱动程序,而不需要修改主要的代码逻辑。
这个例子展示了静态工厂方法在JDBC服务提供者框架中的应用,其中返回的对象的类在编写包含该方法的类时并不一定存在,而是根据具体的实现在运行时动态加载和使用。
这个太难理解了,感兴趣的读者可以去了解一下服务提供者框架!!
缺点一:
静态工厂方法因为没有共有的或者受保护的构造方法,就无法为这些类创建子类。(因祸得福)
缺点二:
在API文档中可能会很难发现这个方法。(无伤大雅)