Effective Kotlin - 静态工厂方法

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、优点

  • 有独特的方法名

    不同于构造函数,静态工厂方法可以有明确的名称,使得代码更易读和易于理解。例如,valueOfofgetInstancenewInstance等命名可以清晰地描述方法的行为和它返回的对象。

    kotlin 复制代码
     class 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")
             }
         }
     }
  • 调用时可以返回相同对象

    静态工厂方法可以返回现有的对象,而不是每次调用都创建一个新对象,这有助于节省资源,尤其是对于经常使用的对象,如缓存实例、单例等,你也可以联想到享元模式

    kotlin 复制代码
     class 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")
     ​
  • 返回任何/非公共类型的子对象、

    kotlin 复制代码
     open 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)

    1. from------A 类型转换方法,它接受单个参数并返回此类型的相应实例

      kotlin 复制代码
       fun from(instant: Instant): Date {
           // 转换 Instant 为 Date
           return Date(...)
       }
    2. of------一个聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起

      kotlin 复制代码
       fun of(vararg elements: Card): EnumSet {
           // 创建并返回一个包含指定元素的 EnumSet
           return EnumSet(...)
       }
    3. valueOf------from 和 to 更为详细的替代 方式

      kotlin 复制代码
       fun valueOf(value: Long): BigInteger {
           // 转换 long 为 BigInteger
           return BigInteger(...)
       }
    4. instance 或 getinstance------返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值

      kotlin 复制代码
       fun getInstance(options: EnumSet<...>): StackWalker {
           // 返回根据选项配置的 StackWalker 实例
           return StackWalker(...)
       }
    5. create 或 newInstance------与 instance 或 getInstance 类似,除了该方法保证每个调用返回一个新的实例

      kotlin 复制代码
       fun <T> newInstance(classObject: Class<T>, arrayLen: Int): Array<T> {
           // 创建并返回一个新的数组实例
           return Array(...)
       }
    6. getType------与 getInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型

      kotlin 复制代码
       fun getFileStore(path: Path): FileStore {
           // 根据路径返回 FileStore
           return FileStore(...)
       }
    7. newType------与 newInstance 类似,但是如果在工厂方法中不同的类中使用。Type 是工厂方法返回的对象类型

      kotlin 复制代码
       fun newBufferedReader(path: Path): BufferedReader {
           // 创建并返回一个新的 BufferedReader
           return BufferedReader(...)
       }
    8. type------ getType 和 newType 简洁的替代方式

      kotlin 复制代码
       fun <T> list(legacyLitany: Enumeration<T>): List<T> {
           // 从 Enumeration 转换为 List
           return legacyLitany.toList()
       }

总之,静态工厂方法和公共构造方法都有它们的用途,并且了解它们的相对优点是值得的。通常,静态工厂更可

取,因此避免在没有考虑静态工厂的情况下提供公共构造方法。

相关推荐
LuiChun1 小时前
webview_flutter_android 4.3.0使用
android·flutter
Tanecious.1 小时前
C语言--分支循环实践:猜数字游戏
android·c语言·游戏
闲暇部落3 小时前
kotlin内联函数——takeIf和takeUnless
android·kotlin
张云瀚3 小时前
《Kotlin核心编程》下篇
kotlin·kotlin核心编程
Android西红柿13 小时前
flutter-android混合编译,原生接入
android·flutter
大叔编程奋斗记13 小时前
【Salesforce】审批流程,代理登录 tips
android
命运之手14 小时前
[ Spring ] Spring Cloud Gateway 2025 Comprehensive Overview
java·kotlin·gateway·spring-cloud
程序员江同学15 小时前
Kotlin 技术月报 | 2025 年 1 月
android·kotlin
爱踢球的程序员-116 小时前
Android:View的滑动
android·kotlin·android studio
划水哥~16 小时前
Kotlin单例类
开发语言·kotlin