英文原文
https://www.jacksondunstan.com/articles/3290
枚举擅长创建具有特定值的简单整数类型。它们的主要用途是从许多类似
enum Color { Red, Green, Blue }
的值中选择一个值。但是,如果你在这些选择上附加了数据,那该怎么办呢?如果数据是一种类型用于一种选择,而另一种类型用于另一种选择,该怎么办?如果有两条数据要附加到一个选项,而另一个选项只附加了一个,该怎么办?今天的文章展示了一个简单的模式,您可以在这些情况下使用它来代替枚举,以获得更大的灵活性和可扩展性。请继续阅读,看看如何做到这一点!
假设您有一个登录功能,可以让用户登录到服务器:
void Login(string username, string password, Action<bool> callback);
回调参数成功时调用TRUE,失败时调用FALSE。您通常很快就会意识到,简单的bool不足以表达登录时可能发生的所有错误。下面是您切换到枚举的版本:
enum LoginError
{
Success,
InvalidCredentials,
AccountLocked,
TemporarilyBanned,
PermanentlyBanned,
}
void Login(string username, string password, Action<LoginError> callback);
这比简单的bool要好得多,因为我们可以指定发生了什么类型的错误,而不是简单的“true”或“false”。这可能会对向用户报告错误有很大帮助。这肯定会对可扩展性有很大帮助,因为我们可以在发现错误类型时向枚举添加更多错误类型,而无需更改Login函数的函数签名。
当我们想要将数据附加到这些枚举时,这个简单的枚举就开始出现问题。对于InvalidCredentials,在锁定其帐户之前允许用户再尝试多少次?对于AccountLocked和TemporarilyBanned,这种情况会持续多久?对于临时禁止和永久禁止,禁止的原因是什么?
实际上,我们希望这些类型中的每一个都有一个类,这样我们就有地方放置一个或多个与错误相关的数据。以下是他们查找这些错误的方式:
class InvalidCredentials
{
int RemainingAttempts;
}
class AccountLocked
{
DateTime UnlockDate;
}
class TemporarilyBanned
{
DateTime UnbanDate;
string Reason;
}
class PermanentlyBanned
{
string Reason;
}
你可能会想到更多的字段来添加-禁止日期,账户锁定原因,凭证提示-现在有了一个非常方便的地方来放置它们。如果您也想为成功案例添加一些数据,您甚至可以为其创建一个类。唯一的问题是Login函数的回调参数不能有四种不同的类类型。您不知道会提前得到什么样的错误,所以您甚至不能重载该函数四次。相反,我们需要使用它们都实现的空接口将它们组合在一起:
interface ILoginError
{
}
class InvalidCredentials : ILoginError
{
int RemainingAttempts;
}
class AccountLocked : ILoginError
{
DateTime UnlockDate;
}
class TemporarilyBanned : ILoginError
{
DateTime UnbanDate;
string Reason;
}
class PermanentlyBanned : ILoginError
{
string Reason;
}
现在登录函数的回调可以使用ILoginError:
void Login(string username, string password, Action<ILoginError> callback);
不指定枚举值,而是按如下方式创建错误:
new PermanentlyBanned { Reason = "Cheating" };
在处理错误时,您需要检查每个可能的原因,就像使用枚举一样:
void HandleLogin(ILoginError error)
{
if (error == null)
{
Debug.Log("Success");
return;
}
var invalidCredentials = error as InvalidCredentials;
if (invalidCredentials != null)
{
Debug.LogError(
"Invalid credentials. You have " + invalidCredentials.RemainingAttempts + " more tries."
);
}
var accountLocked = error as AccountLocked;
if (accountLocked != null)
{
Debug.LogError(
"Account locked until " + accountLocked.UnlockDate + "."
);
}
var temporarilyBanned = error as TemporarilyBanned;
if (temporarilyBanned != null)
{
Debug.LogError(
"Banned until " + temporarilyBanned.UnbanDate + " for " + temporarilyBanned.Reason + "."
);
}
var permanentlyBanned = error as PermanentBanned;
if (permanentlyBanned != null)
{
Debug.LogError(
"Banned for " + permanentlyBanned.Reason + "."
);
}
}
这里有三个级别的指定错误:布尔、枚举、类。到目前为止,类方法比bool或enum更灵活和可扩展。它也需要最多的工作来设置,但这在很大程度上是因为您想要指定额外的数据。枚举和bool也是如此:与仅使用true和false相比,使用enum指定错误类型需要更多的设置。
哪一级最适合你?只有你才能决定。你在你的应用程序中使用哪些?在评论中分享你的想法!