如何高效的创建对象

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

引子

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

相关文章
|
7月前
|
Java C#
C# 面向对象编程解析:优势、类和对象、类成员详解
OOP代表面向对象编程。 过程式编程涉及编写执行数据操作的过程或方法,而面向对象编程涉及创建包含数据和方法的对象。 面向对象编程相对于过程式编程具有几个优势: OOP执行速度更快,更容易执行 OOP为程序提供了清晰的结构 OOP有助于保持C#代码DRY("不要重复自己"),并使代码更易于维护、修改和调试 OOP使得能够创建完全可重用的应用程序,编写更少的代码并减少开发时间 提示:"不要重复自己"(DRY)原则是有关减少代码重复的原则。应该提取出应用程序中常见的代码,并将其放置在单一位置并重复使用,而不是重复编写。
75 0
|
设计模式 Java
创建对象的方式有哪些
创建对象的方式有哪些
|
7月前
|
设计模式
二十三种设计模式全面解析-组合模式与享元模式的结合应用:实现对象的共享和高效管理
二十三种设计模式全面解析-组合模式与享元模式的结合应用:实现对象的共享和高效管理
|
1月前
|
存储 JavaScript 前端开发
构造函数继承有什么缺点?
【10月更文挑战第26天】构造函数继承虽然能够实现属性的继承,但在方法继承、内存使用效率、访问父类原型属性以及实现多态性等方面存在一些缺点。在实际开发中,可以根据具体的需求和场景,结合其他继承方式来综合解决这些问题,以实现更高效、更灵活的继承机制。
35 8
|
2月前
|
设计模式
用建造者模式的思想改造构造方法。灵活,快捷的链式创建对象
【10月更文挑战第4天】该文本介绍使用建造者模式改造构造方法,以实现更灵活、快捷的对象创建。建造者模式将复杂对象的构建过程与表示分离,提高代码的灵活性和可维护性。针对传统构造方法参数过多、难以灵活设置属性等问题,通过创建产品类、建造者抽象类和具体建造者类,并采用链式调用来简化对象创建过程。
|
7月前
|
设计模式 JavaScript 前端开发
JavaScript工厂模式:创建对象的简便方式!
JavaScript工厂模式:创建对象的简便方式!
|
6月前
|
JavaScript 前端开发
深入解析JavaScript中的面向对象编程,包括对象的基本概念、创建对象的方法、继承机制以及面向对象编程的优势
【6月更文挑战第12天】本文探讨JavaScript中的面向对象编程,解释了对象的基本概念,如属性和方法,以及基于原型的结构。介绍了创建对象的四种方法:字面量、构造函数、Object.create()和ES6的class关键字。还阐述了继承机制,包括原型链和ES6的class继承,并强调了面向对象编程的代码复用和模块化优势。
62 0
|
设计模式 缓存 Java
JAVA设计模式12:享元模式,避免创建大量相似对象的开销
JAVA设计模式12:享元模式,避免创建大量相似对象的开销
|
Java C++
面对对象三大特性:封装、继承、多态
面对对象三大特性:封装、继承、多态
|
存储 设计模式 Java
怎么更快地去理解工厂模式
怎么更快地去理解工厂模式
88 0