如何在 Kotlin 中的数据类上实现空对象模式?



我有一个 Kotlin 数据类:

data class PaymentAccount(
val accountId: Int,
val accountNumber: String,
val title: String
)

这就是我在 Java 中会做的事情:

创建一个抽象类:

public abstract class PaymentAccount {
protected int accountId;
protected String accountNumber;
protected String title;
public PaymentAccount(int accountId,
String accountNumber,
String title) {
this.accountId = accountId;
this.accountNumber = accountNumber;
this.title = title;
}
}

创建空对象并扩展抽象类:

public class NullPaymentAccount extends PaymentAccount {
public NullPaymentAccount() {
super(-1,
"Invalid account number",
"Invalid title");
}
}

创建一个真实的对象并扩展抽象类:

public class RealPaymentAccount extends PaymentAccount {
public RealPaymentAccount(int accountId,
String accountNumber,
String title) {
super(accountId,
accountNumber,
title);
}
}

如何在 Kotlin 中正确实现空对象模式?有不止一种方法吗?如果是这样,最简洁优雅的方式是什么?

在 Kotlin 中,你可以做同样的事情,只是代码行更少:

interface Account {
val accountId: Int
val accountNumber: String
val title: String
}
object EmptyAccount : Account {
override val accountId: Int = 1
override val accountNumber: String = ""
override val title: String = ""
}
data class PaymentAccount(
override val accountId: Int,
override val accountNumber: String,
override val title: String): Account

请注意,为了提高效率,我们还制作EmptyAccount单调。

虽然已经为您提供的解决方案很好,但如果默认值不是全部或全无,则可能不需要显式类来表示 null 状态。我认为为所有字段提供默认值空对象模式。

例如,你可以像这样编写你的类:

data class PaymentAccount(
val accountId: Int = -1,
val accountNumber: String = "Invalid Account Number",
val title: String = "Invalid Title"
)

当您构建它们时:

PaymentAccount(1, "Acct2", "Checking") // Actual data
PaymentAccount() // Default values, therefore a "null" object.

唯一真正的问题是当您只指定某些值时,但这可能是可以/可取的:

PaymentAccount(1) // accountNumber and title have defaults

最好使用sealed interfacesealed class.例如:

sealed interface Account {
val accountId: Int
val accountNumber: String
val title: String
object Empty : Account {
override val accountId: Int = 1
override val accountNumber: String = ""
override val title: String = ""
}
data class Payment(
override val accountId: Int,
override val accountNumber: String,
override val title: String
) : Account
}

用法:

val account = findAccountById(id = 1)
when (account) {
Account.Empty -> TODO()
is Account.Payment -> TODO()
}

哪里:

val list = listOf(
Account.Payment(
accountId = 1,
accountNumber = "1",
title = "Bob"
)
)
private fun findAccountById(id: Int): Account {
return list.firstOrNull { it.accountId == id }?:Account.Empty
}

另一种方法是为此定义一个辅助构造函数:

data class PaymentAccount(
val accountId: Int,
val accountNumber: String,
val title: String
){
constructor() : this(-1,
"Invalid account number",
"Invalid title")
}

相关内容

  • 没有找到相关文章

最新更新