1、前言
活跃下我自己的脑子,根据Effective Java 写的,阿弥陀佛。
2、静态工厂方法
考虑使用静态工厂方法替代构造方法(静态工厂方法与设计模式中的工厂方法模式不同。这里描述的静态工厂方法在设计模式中,没有直接的等价):获取一个类一般我们使用它的公共构造方法,也可以提供静态工厂方法。
Kotlin 中的类不能有静态成员。作为替代,Kotlin 使用伴生对象(companion object
)来实现类似静态成员的功能
kotlin
class Book private constructor(val title: String, val author: String) {
companion object {
fun create(title: String, author: String): Book {
return Book(title, author)
}
}
}
// 使用
val book = Book.create("Effective Kotlin", "ZhangYiChi")
3、优点
-
有独特的方法名
不同于构造函数,静态工厂方法可以有明确的名称,使得代码更易读和易于理解。例如,
valueOf
、of
、getInstance
、newInstance
等命名可以清晰地描述方法的行为和它返回的对象。kotlinclass Book private constructor(val title: String, val author: String) { companion object { fun create(title: String, author: String): Book { return Book(title, author) } fun createYellowBook(): Book { return Book("Yellow", "Yellow Man") } fun createGreenBook(): Book { return Book("Green", "Green Man") } } }
-
调用时可以返回相同对象
静态工厂方法可以返回现有的对象,而不是每次调用都创建一个新对象,这有助于节省资源,尤其是对于经常使用的对象,如缓存实例、单例等,你也可以联想到享元模式
kotlinclass DatabaseConnection private constructor(val connectionString: String) { companion object { private val cache = mutableMapOf<String, DatabaseConnection>() fun getInstance(connectionString: String): DatabaseConnection { return cache.getOrPut(connectionString) { DatabaseConnection(connectionString) } } } } // 使用 val dbConnection1 = DatabaseConnection.getInstance("connectionString1") val dbConnection2 = DatabaseConnection.getInstance("connectionString1")
-
返回任何/非公共类型的子对象、
kotlinopen class Shape { //这是私有的哦 private class Circle(val radius: Double) : Shape() companion object { fun newCircleShape(radius: Double): Shape { return Circle(radius) } } } //使用 val shape: Shape = Shape.newCircleShape(1.0)
-
顶层函数
顶层函数是定义在类之外的函数,它们不属于任何类,但可以在整个应用程序中访问。
你可以在任意类中放入你的函数
kotlin//放在这 fun createShape() : Shape { return Shape() } open class Shape { private class Circle(val radius: Double) : Shape() companion object { fun newCircleShape(radius: Double): Shape { return Circle(radius) } } } //使用 val shape: Shape = createShape()
4、缺点
-
不能被子类化
如果一个类只有私有构造函数和静态工厂方法,那么它不能被子类化。这对于某些设计是一个限制,尤其是在希望通过扩展来增加或修改类功能的场景中。不过这本身就是静态工厂方法的特性,算不上缺点。福祸相依。
-
难以找到
因为名字很随心,新的开发人员可能不会意识到要通过静态方法来创建类的实例。当然可以通过一定的规范来约束,比如:
(省略了companion object)
-
from------A 类型转换方法,它接受单个参数并返回此类型的相应实例
kotlinfun from(instant: Instant): Date { // 转换 Instant 为 Date return Date(...) }
-
of------一个聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起
kotlinfun of(vararg elements: Card): EnumSet { // 创建并返回一个包含指定元素的 EnumSet return EnumSet(...) }
-
valueOf------from 和 to 更为详细的替代 方式
kotlinfun valueOf(value: Long): BigInteger { // 转换 long 为 BigInteger return BigInteger(...) }
-
instance 或 getinstance------返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值
kotlinfun getInstance(options: EnumSet<...>): StackWalker { // 返回根据选项配置的 StackWalker 实例 return StackWalker(...) }
-
create 或 newInstance------与 instance 或 getInstance 类似,除了该方法保证每个调用返回一个新的实例
kotlinfun <T> newInstance(classObject: Class<T>, arrayLen: Int): Array<T> { // 创建并返回一个新的数组实例 return Array(...) }
-
getType------与 getInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型
kotlinfun getFileStore(path: Path): FileStore { // 根据路径返回 FileStore return FileStore(...) }
-
newType------与 newInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型
kotlinfun newBufferedReader(path: Path): BufferedReader { // 创建并返回一个新的 BufferedReader return BufferedReader(...) }
-
type------ getType 和 newType 简洁的替代方式
kotlinfun <T> list(legacyLitany: Enumeration<T>): List<T> { // 从 Enumeration 转换为 List return legacyLitany.toList() }
-
总之,静态工厂方法和公共构造方法都有它们的用途,并且了解它们的相对优点是值得的。通常,静态工厂更可
取,因此避免在没有考虑静态工厂的情况下提供公共构造方法。