Swift tricks-Phantom Types

Swift tricks系列收集Swift牛逼的patterns和让你代码更加Swifty的tricks,持续更新中……

Phantom Types

在项目中,某些业务是需要按照严格的流程和规范进行的,举个

func getSecretData() -> String {
    return "secretedata";
}
func encrypt(secretData : String) -> String {
    return "encryptdata";
}
func sendEncryptData(encryptdata : String){
    // send encrypt data
}
//首先获取秘密信息
var secretedata = getSecretData()
//对秘密信息加密
var encryptdata = encrypt(secretedata)
//发送加密信息
sendEncryptData(encryptdata)

上面的例子必须严格按照“获取信息”->“加密”->“发送”的流程来,否则就会产生安全问题!
但是程序员是人,是人就会犯错误。如果一个粗心的程序员写了下面的代码,那将会产生灾难性的后果:

var secretedata = getSecretData()
sendEncryptData(secretedata)

肿么办?能不能通过代码来保证流程呢?Yes, we can!
一般的做法是酱紫的:

struct SecretData {
    let secretedata:String
}

struct EncryptData {
    let encryptdata:String
}

func getSecretData() -> SecretData {
    return SecretData(secretedata:"secretedata");
}
func encrypt(secretData : SecretData) -> EncryptData {
    return EncryptData(encryptdata:"encryptdata");
}
func sendEncryptData(encryptdata : EncryptData){
    // send encrypt data
}
var secretedata = getSecretData()
var encryptdata = encrypt(secretedata)
sendEncryptData(encryptdata)

这样我们就能避免粗心程序员造成的错误 。因为当你试图执行sendEncryptData(secretedata)的时候,编译器会报错!


在上面的方法中,我们定义了两个struct,这两个struct除了名字不一样外,其他都是一模一样。设想一下,如果struct里面的字段稍微多一点,我们的代码将是这样的:

struct SecretData {
    let secretedata:String
    let encyptMehod:String
    let encyptKey:String
    let from:String
    let to:String
    ......
}

struct EncryptData {
    let encryptdata:String
    let encyptMehod:String
    let encyptKey:String
    let from:String
    let to:String
    ......
}

这……就有点不怎么Swifty了。
肿么办?


Phantom Types!

enum Encrypted {}
enum Decrypted {}

struct SecretData {
    let secretedata:String
    let encyptMehod:String
    let encyptKey:String
    let from:String
    let to:String
}

func getSecretData() -> SecretData {
    return SecretData(secretedata:"secretedata", encyptMehod:"nb", encyptKey:"xxx",from:"agent",to:"gcd");
}
func encrypt(secretData : SecretData) -> SecretData {
    return SecretData(secretedata:"secretedata", encyptMehod:"nb", encyptKey:"xxx",from:"agent",to:"gcd");
}
func sendEncryptData(encryptdata : SecretData)
{
    // send encrypt data
}
var secretedata = getSecretData()
var encryptdata = encrypt(secretedata)
sendEncryptData(encryptdata)

EncryptedDecrypted是两个Phantom Type,我们通过一个范型struct解决了重复定义属性的问题。

PS:看到没有case的enum不要惊讶,这是Phantom Type的精髓

参考:Functional Snippet #13: Phantom Types

你可能感兴趣的:(Swift tricks-Phantom Types)