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

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

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

相关推荐
吃汉堡吃到饱1 小时前
【Android】浅析MVC与MVP
android·mvc
深海呐8 小时前
Android AlertDialog圆角背景不生效的问题
android
ljl_jiaLiang8 小时前
android10 系统定制:增加应用使用数据埋点,应用使用时长统计
android·系统定制
花花鱼8 小时前
android 删除系统原有的debug.keystore,系统运行的时候,重新生成新的debug.keystore,来完成App的运行。
android
落落落sss9 小时前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
一丝晨光10 小时前
逻辑运算符
java·c++·python·kotlin·c#·c·逻辑运算符
消失的旧时光-194311 小时前
kotlin的密封类
android·开发语言·kotlin
服装学院的IT男12 小时前
【Android 13源码分析】WindowContainer窗口层级-4-Layer树
android
CCTV果冻爽14 小时前
Android 源码集成可卸载 APP
android
码农明明14 小时前
Android源码分析:从源头分析View事件的传递
android·操作系统·源码阅读