为多个枚举创建一个 DRY 函数(枚举子类化?)

Create a DRY function for multiple enums (enum subclassing?)

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

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
        }
    }
}

正如您在此处看到的,两个枚举共享相同的 "titles" 变量。有没有办法我可以创建一个 enum/class 他们可以从中继承此功能?

以下是我尝试过的一些方法:

我考虑过这个,但我不想扩展所有具有 Int rawValues

的函数

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

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

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

您可以使用自定义协议,例如:

protocol HasTitle: CaseIterable {
    var title: String { get }
}

extension HasTitle {
    static var titles : [String] { allCases.map { [=10=].title } }
}

然后让您的枚举符合您的新协议:

enum CustomerTypes: Int, HasTitle {
    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
        }
    }
}

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

您还可以通过使用 map 而不是 for..in 循环并删除无用的 get 说明符来显着简化 titled。 getter 是计算 属性 的默认访问器,您不需要将闭包包装在 get { ... } 中,除非您同时创建 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 .

与您的问题无关,但枚举大小写应该像所有变量一样是小驼峰命名法。

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"
        }
    }
}