首页 > 解决方案 > 为多个枚举创建一个 DRY 函数(枚举子类化?)

问题描述

我有多个枚举,它们都将共享相同的功能。有没有办法编写一次这个函数并让它出现在所有指定的枚举中?这是一个例子:

enum CustomerTypes: Int, CaseIterable {
    case NewCustomer = 0
    case ExistingCustomer
    case Myself

    private var title: String {
        switch self {
        case .NewCustomer : return StandardStrings.NewDrive.NewCustomer.string
        case .ExistingCustomer : return StandardStrings.NewDrive.ExistingCustomer.string
        case .Myself : return StandardStrings.NewDrive.Myself.string
        }
    }

    static var titles: [String] {
        get {
            var toReturn: [String] = []
            for value in allCases {
                toReturn.append(value.title)
            }

            return toReturn
        }
    }
}

enum EnquiryTypes: Int, CaseIterable {
    case Phone = 0
    case FaceToFace

    private var title: String {
        switch self {
        case .Phone : return StandardStrings.Misc.Phone.string
        case .FaceToFace : return StandardStrings.Misc.FaceToFace.string
        }
    }

    static var titles: [String] {
        get {
            var toReturn: [String] = []
            for value in allCases {
                toReturn.append(value.title)
            }

            return toReturn
        }
    }
}

正如您在此处看到的,两个枚举共享相同的“标题”变量。有没有办法我可以创建一个枚举/类,他们可以从中继承这个函数?

以下是我尝试过的一些事情:
你能扩展一个枚举吗?
我考虑过这一点,但我不想扩展所有具有 Int rawValues 的函数

我考虑创建一个协议,然后创建一个采用这样的协议的函数,但我仍然需要在每个枚举上实现 _allCases (因为你不能从 CaseIterable 继承):

protocol RBEnum {
    var title: String { get }
    var _allCases: [RBEnum] { get }
}

那么有什么想法可以避免在这些枚举上违反 DRY 原则吗?

标签: swiftenumsdry

解决方案


协议是正确的方法。不知道为什么你认为协议不能相互继承,但它们可以,所以你可以让你的协议继承自CaseIterable.

您还可以titled通过使用map而不是for..in循环并摆脱无用的get说明符来显着简化。get { ... }getter 是计算属性的默认访问器,除非您同时创建 getter 和 setter ,否则不需要将闭包包装起来。

protocol Titled: CaseIterable {
    var title: String { get }
    static var titles: [String] { get }
}

extension Titled {
    static var titles: [String] { allCases.map(\.title) }
}

然后,您只需将title属性保留在您的枚举中,并使它们符合Titled并且由于您titles免费获得的默认实现。

与您的问题无关,但枚举案例应该像所有变量一样为 lowerCamelCase。

enum CustomerTypes: Int, Titled {
    case newCustomer = 0
    case existingCustomer
    case myself

    var title: String {
        switch self {
        case .newCustomer : return "new"
        case .existingCustomer : return "existing"
        case .myself : return "my"
        }
    }
}

enum EnquiryTypes: Int, Titled {
    case phone = 0
    case faceToFace

    var title: String {
        switch self {
        case .phone : return "phone"
        case .faceToFace : return "face"
        }
    }
}

推荐阅读