为什么说静态工厂方法可能会比构造器更好?听说读完就会有一个女朋友?

2024-06-15 07:32

本文主要是介绍为什么说静态工厂方法可能会比构造器更好?听说读完就会有一个女朋友?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 什么是静态工厂方法
    • 静态工厂方法比构造器好在哪里
      • 静态工厂方法有名称而构造器没有(前者可读性更好)
      • 不必每次调用它们的时候都创建一个新对象
      • 可以返回原返回类型的任何子类对象
      • 创建泛型对象可以更加简洁
    • 静态工厂的局限之处
    • 总结

前言:相信读过《Effective Java》(第二版)的小伙伴知道我在说什么,作者在书中总结了78条黄金建议,其中建议的第一条就是:考虑用静态工厂方法替代构造器。可以说是开幕雷击,第一条我就懵X了,什么是静态工厂方法?为什么要替代构造器?是构造器不香吗?本文将根据这些疑问刨根问底,详细分析静态工厂方法的优劣,相信我,有问题欢迎评论指出,本篇文章一定不会枯燥,坚持读完哦~

在这里插入图片描述

什么是静态工厂方法

当我们想要获得一个类的实例对象的时候,恐怕一下子就通过new一个对象来获得了。那么静态工厂方法是怎么实现的呢?其实也很简单:

public static Girl newGirlFriend(boolean isBeautifulGirl) {return new Girl(isBeautifulGirl);
}

如此,我们通过类名加newGirlFriend就可以轻松地拿到对象。

所谓的静态工厂方法就是不通过new,而通过一个静态方法返回自身的实例对象

静态工厂方法比构造器好在哪里

由《Effective Java》可以得到四点静态工厂方法比构造器好的地方:
①静态工厂方法有名称而构造器没有(前者可读性更好)
②不必每次调用它们的时候都创建一个新对象
③可以返回原返回类型的任何子类对象(不局限于单一特定的类)
④创建泛型对象可以更加简洁

静态工厂方法有名称而构造器没有(前者可读性更好)

说到有名称这点,构造器是真的没法儿比:

public class GirlFriend {private boolean isBeautiful;private boolean isTall;public GirlFriend(){}public GirlFriend(boolean isBeautiful) {this.isBeautiful = isBeautiful;    }public GirlFriend(boolean isBeautiful, boolean isTall) {this.isBeautiful = isBeautiful;    this.isTall = isTall;    }
}

调用者如果不是非常熟悉这段代码,必须要看文档中有哪些重载的构造方法,稍有不慎,就会调错,毕竟构造方法都是一个名字,只有参数不同而已。但是静态工厂方法就不一样了,可以起很多能让调用者见名知意的名字:getBeautifulGirlfriend(); getTallGirl();,是不是看出差距了

另外:正是因为这一特性,所以哪怕他们有相同的参数,也不会报错,如果构造器有两个构造方法含有相同参数,必定出错,但是任性的静态工厂方法想怎么起名字就怎么起名字,完美避过了这个坑~
在这里插入图片描述

不必每次调用它们的时候都创建一个新对象

当我们需要获得类的实例对象的时候,为了性能,我们不在乎他是不是新对象,使用new必然会得到一个不同地址的对象(姑且称之为新对象),当我们使用new GirlFriend();这种方式直接创建对象,相当于对JVM说,我要一个对象,然后JVM会去根据双亲委派原则加载验证准备解析(new一个对象发生了什么?),所以开支是蛮大的,尤其在重复新建一个对象的时候。小斌哥我之前的代码就都是这种毛病,并没有使用单例模式,每个方法都new同一个对象,我去,简直是伤害了我的CPU,心疼我的旧电脑,怪不得那么快就挂了(玩笑话);使用静态工厂方法最简单的一个例子就是单例模式,我们可以确保获取多个对象的时候只需要创建一次对象并且销毁一次对象,这样就很“环保”了,对内存的开支会达到最小,这点是构造器望尘莫及的。

说到单例模式,大家会想到“饿汉式”与“懒汉式”,举个最简单的例子不考虑线程安全给大家展示一下单例模式是如何做到多次获取对象只创建并销毁一次:
饿汉式:

public class Singleton{private static Singleton singleton = new Singleton ();private Singleton (){}public static Singleton getInstance(){return singleton;
}

懒汉式:

public class Singleton{private static Singleton singleton = null;public static Singleton getInstance(){if(singleton==null){singleton = new Singleton();}return singleton;}
}

使用单例模式不管创建多少次都会返回相同的对象,所以相当于对象被多次循环利用了,提升了效率。在这里插入图片描述

可以返回原返回类型的任何子类对象

这体现了里氏原则:任何基类可以出现的地方,子类一定可以出现。 比如有这样的UML:
在这里插入图片描述

public static Singleton getGirlFriend(){return new 女朋友();//可以返回新垣结衣()、长泽雅美()、松冈茉优()、绫濑遥()//因为都是女朋友的子类
}

这个优点有些欺负构造器了,毕竟它没有返回值。

创建泛型对象可以更加简洁

作者想表示过去泛型书写比较复杂,比如:

Map<String, List<String>> map = new HashMap<String, List<String>>(); 

额,但是jdk1.7之后这个问题已经木有了,毕竟这本书有一定年头了(第二版参考的是jdk1.6),所以就当这条没有吧。

另外,静态工厂方法还有其他好处,比如可以隐藏实现细节,只提供用户最简单的方法入口,比如让你写一个计算器软件,用户只需要输入:3*(7/1.455)+11-12,而方法的具体实现细节是私有的,用户是看不到的,也不需要看到,否则就体现不了封装的特性了,一个是用户使用着麻烦,另外是出错的可能性更大,你暴露给用户更多的参数更多的方法,出BUG的可能性就更大。这就好比现在的手机,只有关机键、音量键,如果把手机后盖拆开暴露给你,手机被整坏的可能性必然会提升啊。。

我们熟知的工具类Collections就是一个很好的例子,他把构造器设置为私有,所以调用者不能通过new来调用类中的方法,只能通过类名加方法名去调用,并且内部需要计算的方法都设为private,调用者看不到也不需要去知道,比如sort方法和binarySearch等。

静态工厂的局限之处

凡事都是两面的,虽然静态工厂方法很好,但是它只要构造方法私有化了,就不能被实例化,也就是说,想让拒绝访问构造器的类拥有子类是不可能的(就像做了绝育手术)。第二点就是它跟普通的静态方法没啥两样,虽然我们管它叫静态工厂方法,但是它依然只是一个很简单的静态方法而已,并不像构造器,有自己的专属名称,还可以在API文档中看到他的名字。但是静态工厂方法也会有一些不成文的规定,正如我们会看到一些newInstance()、valueOf()、getInstance()等,这些往往就是静态工厂方法实现的。

总结

作者给我们这条建议,并非让我们用静态构造方法彻底替换构造器,只是希望我们在以后可以有多一种选择,直接new并不是唯一的方法,他们各有各的好,需要我们去进行合适的选择。

这篇关于为什么说静态工厂方法可能会比构造器更好?听说读完就会有一个女朋友?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062813

相关文章

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

macOS无效Launchpad图标轻松删除的4 种实用方法

《macOS无效Launchpad图标轻松删除的4种实用方法》mac中不在appstore上下载的应用经常在删除后它的图标还残留在launchpad中,并且长按图标也不会出现删除符号,下面解决这个问... 在 MACOS 上,Launchpad(也就是「启动台」)是一个便捷的 App 启动工具。但有时候,应

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

浅谈mysql的sql_mode可能会限制你的查询

《浅谈mysql的sql_mode可能会限制你的查询》本文主要介绍了浅谈mysql的sql_mode可能会限制你的查询,这个问题主要说明的是,我们写的sql查询语句违背了聚合函数groupby的规则... 目录场景:问题描述原因分析:解决方案:第一种:修改后,只有当前生效,若是mysql服务重启,就会失效;

CentOS 7部署主域名服务器 DNS的方法

《CentOS7部署主域名服务器DNS的方法》文章详细介绍了在CentOS7上部署主域名服务器DNS的步骤,包括安装BIND服务、配置DNS服务、添加域名区域、创建区域文件、配置反向解析、检查配置... 目录1. 安装 BIND 服务和工具2.  配置 BIND 服务3 . 添加你的域名区域配置4.创建区域