引子
事情是这样的,今天写了单元测试下一个hsf服务,查一下最近一个月的数据
@Test
public void testServiceList(){
ActivityDTO dto = new ActivityDTO();
activity.setStartDate(new Date(2022, 3, 1, 0, 0, 0));
activity.setEndDate(new Date(2022, 3, 31 0, 0, 0));
// 最近一个月的数据肯定是有的,结果发现什么都没查到...
List<Activity> list = activityService.list(dto);
}
没多久就定位问题了,打开了Date的构造方法查看源码,不经吐槽:
我以为构造出的年月日,你却做了这么多处理,往后推迟了1900年1个月!怪不得落得“过时”的下场。
@Deprecated
public Date(int year, int month, int date, int hrs, int min, int sec) {
int y = year + 1900;
// month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
if (month >= 12) {
y += month / 12;
month %= 12;
} else if (month < 0) {
y += CalendarUtils.floorDivide(month, 12);
month = CalendarUtils.mod(month, 12);
}
BaseCalendar cal = getCalendarSystem(y);
cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
getTimeImpl();
cdate = null;
}
不禁思考,以后怎样避免这样的问题。
难道以后想创建某些对象,都得点进去看下源码,看下构造器是如何处理的?
当然没必要,我们其实可以有更好的方案——静态工厂方法。
下面我们就通过几个典型例子认识下它的优点:
静态工厂方法
1. 方法名称即可表达创建对象的含义
LocalDateTime now = LocalDateTime.now();
LocalDateTime localDateTime = LocalDateTime.of(2022, 3, 1, 0, 0, 0);
// 构造器表意不明
new Date();
new Date(2022, 3, 1, 0, 0, 0);
2. 不一定要创建新的对象
// 当值在low,high 之间时,如Integer.valueOf(1)是没有创建新的Integer对象,而是取的缓存
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
3. 可以返回原类型的任何子类型对象
// 构造方法只能返回确切的自身类型,而静态工厂方法则能够更加灵活,可以根据需要方便地返回任何它的子类型的实例
// (Collections)SingletonList是私有内部类,extends AbstractList<E>
public static <T> List<T> singletonList(T o) {
return new SingletonList<>(o);
}
// EmptyList是私有内部类,extends AbstractList<E>
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
4. 减少对外暴露不必要的属性
public class Company {
public static final int TYPE_TECHNOLOGY = 1;
public static final int TYPE_INTELLIGENT = 2;
public static final int TYPE_INTERNATIONAL = 3;
int type;
/**
* 限制外部创建非定义对象
* 如:new Company(4)
*/
private Company(int type) {
this.type = type;
}
public static Company newTechnology() {
return new Company(TYPE_TECHNOLOGY);
}
public static Company newIntelligent () {
return new Company(TYPE_INTELLIGENT);
}
public static Company newInternational() {
return new Company(TYPE_INTERNATIONAL);
}
}
简而言之,创建对象优先使用工厂方法,这个可以减少调用者出错的机率;
类的提供者对入口的改造和构造方法的限制,可以让更加有效的控制类。
正如《Effective Java》建议:考虑使用静态工厂方法代替构造器