Сегодня кто-то прокомментировал этот код и предположил, что было бы лучше в enum:

typealias PolicyType = (filename: String, text: String)

struct Policy {
  static let first = PolicyType(filename: "firstFile.txt", text: "text in first file")
  static let second = PolicyType(filename: "secondFile.txt", text: "text in second file")
  static let third = PolicyType(filename: "thirdFile.txt", text: "text in third file")
}

let thirdPolicyText = Policy.third.text

Есть ли более эффективный и удобный в обслуживании способ сделать это с помощью перечисления? Моя основная задача - ремонтопригодность.

Вот что я придумал:

enum Policy: RawRepresentable {
  case one
  case two
  case three

  var rawValue: (filename: String, text: String) {
    switch self {
    case .one:
      return ("1", "policy 1 text")
    case .two:
      return ("2", "policy 2 text")
    case .three:
      return ("3", "policy 3 text")
    }
  }

  init?(rawValue: (filename: String, text: String)) {
    switch rawValue {
    case ("1", "policy 1 text"):
      self = .one
    case ("2", "policy 2 text"):
      self = .two
    case ("3", "policy 3 text"):
      self = .three
    default:
      return nil
    }
  }
}

На этом этапе я выяснил, как достичь аналогичной функциональности с помощью struct и enum. enum кажется гораздо более сложной задачей, если кто-то вернется, чтобы обновить его, и это более подвержено ошибкам. Пол Хегарти говорит, что линия, которая не будет сбой, - это строка, которую вы не пишете, а маршрут enum выглядит и кажется громоздким.

Есть ли преимущество в памяти у маршрута enum по сравнению с маршрутом struct?

Когда я закончу, я хотел бы иметь возможность передавать политику в качестве параметра, например:

func test(for policy: Policy) {
  print(policy.rawValue.filename)
  print(policy.rawValue.text)
}

test(for: Policy.first)
2
Adrian 21 Сен 2018 в 04:14

2 ответа

Лучший ответ

Единственное улучшение при использовании перечисления, которое я могу придумать, - это просто заменить ключевое слово struct на ключевое слово enum:

enum Policy {
  static let first = PolicyType(filename: "firstFile.txt", text: "text in first file")
  static let second = PolicyType(filename: "secondFile.txt", text: "text in second file")
  static let third = PolicyType(filename: "thirdFile.txt", text: "text in third file")
}

Перечисления без вариантов невозможно создать, поэтому разработчики могут использовать только определенные типы статической политики.

Функция как это:

func cantBeCalled(policy: Policy) { }

Не может быть вызван из вашего кода, поскольку невозможно построить (выделить) Policy.

Тем не менее, я бы сохранил структуру и переделал все в один тип:

struct Policy {
    static let first = Policy(filename: "firstFile.txt", text: "text in first file")
    static let second = Policy(filename: "secondFile.txt", text: "text in second file")
    static let third = Policy(filename: "thirdFile.txt", text: "text in third file")

    public let filename: String
    public let text: String

    private init(filename: String, text: String) {
        self.filename = filename
        self.text = text
    }
}

Структура лучше отображает вашу проблемную область, поскольку вам нужен контейнер, который будет содержать два свойства. Кортежи не подходят для масштабирования, когда количество деталей растет, и ими труднее управлять (например, они не могут соответствовать протоколам).

Этот новый дизайн структуры имеет те же преимущества, что и приведенное выше перечисление: нельзя создавать политики «вручную», доступен только набор предопределенных политик. И дает больше преимуществ: только один тип, лучшая семантика для контейнера, возможность использовать протоколы для типа Policy, отсутствие неоднозначного доступа к свойствам (к членам помеченного кортежа можно получить доступ либо через метку, либо или через индекс).

1
Cristik 26 Сен 2018 в 05:58

Вот возможность. Это немного длинновато, но это Swifty:

enum Policy {
    case one, two, three

    var filename: String {
        switch self {
        case .one: return "Policy 1 name"
        case .two: return "Policy 2 name"
        case .three: return "Policy 3 name"
        }
    }

    var text: String {
        switch self {
        case .one: return "Policy 1 text"
        case .two: return "Policy 2 text"
        case .three: return "Policy 3 text"
        }
    }
}

Проблема с перечислениями Swift на данный момент заключается в том, что они ограничены RawValues. Недавно я столкнулся с подобной ситуацией, и я тоже попытался использовать перечисление вместо структуры. Я даже экспериментировал с именованным кортежем. Но в итоге я использовал структуру.

3
Daniel 21 Сен 2018 в 02:19