如何高效的创建对象

简介: 不禁思考,以后怎样避免这样的问题。难道以后想创建某些对象,都得点进去看下源码,看下构造器是如何处理的?当然没必要,我们其实可以有更好的方案——静态工厂方法。

引子

事情是这样的,今天写了单元测试下一个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》建议:考虑使用静态工厂方法代替构造器

相关文章
|
6月前
|
C++
C++实现单例模式-多种方式比较
单例模式,面试中经常被问到,但是很多人只会最简单的单例模型,可能连多线程都没考虑到,本文章从最简单的单例,到认为是最佳的单例模式实现方式,单例模式没有什么知识点,直接上源码
88 0
|
设计模式 Java
创建对象的方式有哪些
创建对象的方式有哪些
|
1月前
|
设计模式
用建造者模式的思想改造构造方法。灵活,快捷的链式创建对象
【10月更文挑战第4天】该文本介绍使用建造者模式改造构造方法,以实现更灵活、快捷的对象创建。建造者模式将复杂对象的构建过程与表示分离,提高代码的灵活性和可维护性。针对传统构造方法参数过多、难以灵活设置属性等问题,通过创建产品类、建造者抽象类和具体建造者类,并采用链式调用来简化对象创建过程。
|
5月前
|
设计模式 缓存 Java
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
|
6月前
|
设计模式 JavaScript 前端开发
JavaScript工厂模式:创建对象的简便方式!
JavaScript工厂模式:创建对象的简便方式!
|
5月前
|
JavaScript 前端开发
深入解析JavaScript中的面向对象编程,包括对象的基本概念、创建对象的方法、继承机制以及面向对象编程的优势
【6月更文挑战第12天】本文探讨JavaScript中的面向对象编程,解释了对象的基本概念,如属性和方法,以及基于原型的结构。介绍了创建对象的四种方法:字面量、构造函数、Object.create()和ES6的class关键字。还阐述了继承机制,包括原型链和ES6的class继承,并强调了面向对象编程的代码复用和模块化优势。
48 0
|
安全 Java 编译器
单例模式的4种实现方式
单例模式的4种实现方式
102 0
|
6月前
|
设计模式 安全 Java
Java设计模式—单例模式的实现方式和使用场景
那么为什么要有单例模式呢?这是因为有的对象的创建和销毁开销比较大,比如数据库的连接对象。所以我们就可以使用单例模式来对这些对象进行复用,从而避免频繁创建对象而造成大量的资源开销。
149 1
|
存储 设计模式 Java
怎么更快地去理解工厂模式
怎么更快地去理解工厂模式
82 0
|
编译器 程序员 C++
高效学 C++|组合类的构造函数
设计好MyString类后,就可以像使用普通类型一样使用它了。例如,类的对象可以像普通的变量一样作为另一个类的数据成员。
193 0
高效学 C++|组合类的构造函数