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()
       }

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

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

相关推荐
CYRUS_STUDIO2 小时前
利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试
android·安全·逆向
CYRUS_STUDIO2 小时前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
黄林晴6 小时前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我6 小时前
flutter 之真手势冲突处理
android·flutter
法的空间6 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止6 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭6 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech7 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831677 小时前
为何Handler的postDelayed不适合精准定时任务?
android
叽哥7 小时前
Kotlin学习第 8 课:Kotlin 进阶特性:简化代码与提升效率
android·java·kotlin