Back
Featured image of post 设计模式之工厂

设计模式之工厂

静态工厂

Java 和 Kotlin 库中不乏这样的例子。

比如 Long.valueOf("1")Channel()

相较于构造器,有一些显而易见的优点:

  1. 不同的构造行为能够具有不同的名称
  2. 能抛异常
  3. 工厂函数可以 suspend

由于构造对象的过程完全可控,更有以下优点:

  1. 缓存,可以检测是否对象存在已在缓存中,从而减少资源占用
  2. 多态,方法返回值并没有被限制,你可以返回该类型,或该类型的子类
  3. 可以使用 inline reified

在 Kotlin 中编写静态工厂有几种常见的做法:

使用 companion object

class Server private constructor(url: URL) {
  companion object {
    fun create(ip: String, port: Int = 8080): Server =
      Server(URL(ip = ip, port = port))
  }
}

companion object 即为伴生对象,和之前讲的 object 一样,是和对应类绑定的单例。在使用方法和 Java 的静态方法没有区别。Server.create("localhost") 即可。

但请注意,它和 Java 的静态类型并不是一个东西。正如它的名字 object,这会在运行时创建一个对象。如果你想真正地创建静态方法,可以使用 @JvmStatic,但这非常不必要。

顶级函数

public fun <T> listOf(vararg elements: T): List<T> = 
  if (elements.size > 0) elements.asList() else emptyList()

假”构造器”

// Kotlin Stdlib...
public inline fun <T> List(
   size: Int,
   init: (index: Int) -> T
): List<T> = MutableList(size, init)

这种写法和命名被 Kotlin 允许。通常用来为接口提供构造入口。

抽象工厂

抽象工厂就是对子类一系列工厂的封装。

比如解析从服务器来的 JSON 字段为对应的操作。

/**
 * 抽象工厂, 提供所有 Operation 的反序列化支持
 */
object AbstractFactory {
  private val factorys = listOf(SetDelayOp, RefreshListOp)

  private val byType = factorys.associateBy { it.type }

  fun parse(json: JSON): Operation {
    val type: String = json.getField<String>("type").toString()
    val factory = byType[type] ?: error("No such operation type $type")
    factory.de
  }
}

/**
 * 工厂, 要求指定对应的 type, 提供反序列化功能
 */
interface Factory<T> {
  val type: String

  fun deserialize(type: String): T
}

/**
 * Operation 接口, 有具体的 type 信息
 */
interface Operation {
  val type: String
}

/**
 * 瞎编的数据类
 */
data class SetDelayOp(
  override val type: String,
  val delay: Long,
): Operation {
  // companion object 是对应类型的工厂
  companion object : Factory<SetDelayOp> {
    override val type: String = "VENDOR"

    override deserialize(type: String): SetDelayOp {
      // ...
      return operation
    }
  }
}

// 又一个瞎编的数据类...
data class RefreshListOp(
  override val type: String,
  val ownerId: Long,
  val listId: Long,
  val listName: String,
  val content: List<Text>,
): Operation {
  data class Text {
    val author: String,
    val content: String,
  }

  companion object : Factory<RefreshListOp> {
    override val type: String = "VENDOR"

    override deserialize(type: String): RefreshListOp {
      // ...
      return operation
    }
  }
}

所以抽象工厂没什么难理解的,无非是将具体类型的一系列工厂包装起来,提供统一的返回接口。

comments powered by Disqus