🛀

enum型に複数のcomputed propertyを持たせる必要がある場合に、特定の型に閉じ込めるように実装する書き方

2024/03/27に公開

備忘録的に書き残しています

enum型に複数のcomputed propertyを持たせる必要がある場合に、特定の型に閉じ込めるように実装すると、caseを追加した際の変更箇所をより限定することができます

よくあるenum型に実装されるコンピューテッドプロパティ

Swiftのenumではこのような書き方が可能で、よくみられる書き方だと思います

enum ItemType {
    case book
    case journal
    case newspaper

    var description: String {
      switch self {
      case .book:
          return "A book is a medium for recording information in the form of writing or images."
      case .journal:
          return "A journal is a scholarly publication containing articles written by researchers, professors, and other experts."
      case .newspaper:
          return "A newspaper is a publication containing news, information, and advertising, usually printed on low-cost paper."
      }
    }
    
    var pageCount: Int {
        switch self {
        case .book:
            return 300 // 仮のページ数
        case .journal:
            return 100 // 仮のページ数
        case .newspaper:
            return 50 // 仮のページ数
        }
    }
}

特定の型に閉じ込めた場合の書き方

enum ItemType {
    case book
    case journal
    case newspaper

    var properties: ItemProperties {
        switch self {
        case .book:
            return Self.bookProperties
        case .journal:
            return Self.journalProperties
        case .newspaper:
            return Self.newspaperProperties
        }
    }
}

extension ItemType {
    struct ItemProperties {
         var description: String
         var pageCount: Int
     }

    static let bookProperties = ItemProperties(description: "A book is a medium for recording information in the form of writing or images.", pageCount: 300)
    static let journalProperties = ItemProperties(description: "A journal is a scholarly publication containing articles written by researchers, professors, and other experts.", pageCount: 100)
    static let newspaperProperties = ItemProperties(description: "A newspaper is a publication containing news, information, and advertising, usually printed on low-cost paper.", pageCount: 50)
}

関連する値を一つの構造体で表せるので、扱われる値がばらけないで済むため読むべき場所が限定されて見通しがよいです。同時にそれはcaseを追加した場合の変更箇所がより限定されることにもつながります。

複数のプロパティを持つ場合はそれぞれのプロパティにcaseを追加する必要がありますが、それらをまとめた型のプロパティであればcaseの追加は一つで済みます。その分、型のそれぞれの値を書く必要があるわけですが、一箇所にまとまっているのでわかりやすいです。

このような書き方のメリットは、例えばcaseの数が多い場合や関連したプロパティを持たせている場合には実感しやすいように思います。

たとえば、多数のcaseを持つ場合のenumを考えてみます

enum ItemType {
    case book
    case journal
    case newspaper
    case magazine
    case ebook
    case report
    case manual
    case brochure
    case textbook
    case anthology
    
    var description: String {
        switch self {
        case .book:
            return "A book is a medium for recording information in the form of writing or images."
        case .journal:
            return "A journal is a scholarly publication containing articles written by researchers, professors, and other experts."
        case .newspaper:
            return "A newspaper is a publication containing news, information, and advertising."
        case .magazine:
            return "A magazine is a periodical publication with a variety of content."
        case .ebook:
            return "An ebook is a book publication made available in digital form."
        case .report:
            return "A report is a document that presents information in an organized format."
        case .manual:
            return "A manual is a handbook or guide that provides specific information or instructions."
        case .brochure:
            return "A brochure is a small book or magazine containing pictures and information about a product or service."
        case .textbook:
            return "A textbook is a book containing a comprehensive compilation of content in a branch of study."
        case .anthology:
            return "An anthology is a published collection of poems or other pieces of writing."
        }
    }
}

いまはプロパティが一つなのでcaseを一つ追加しておしまいですが、たいてい複数のプロパティを持っていて、それらを記述すると各プロパティが離れてしまい、ケースがどのような値を持っているのかが一見してわかりづらくなります。

このような場合、関連した値をひとつの型として表現してカプセル化をすることで可読性を向上することができます。

一方で、型として表現する場合、柔軟性の低下、冗長性、メモリ使用量の増加、テストの難易度などを考慮する必要があります(ChatGPTありがとう!!)

特定のケースで異なる振る舞いや追加のプロパティが必要になった場合に、既存の型に手を加えるか新しい型を作成する必要があります。仮に新しい型を作ったとしても、共通のプロパティを必要とする場合はありえます。
結果として、コードの冗長性に繋がったり、再利用の妨げになります。

また静的プロパティを利用してプロパティを表しているものの、これらのプロパティは、プログラムの実行中、常に同じ値を保持し、アプリケーションのライフタイム中に一度だけ初期化されます。したがってメモリに常駐するため、多数のプロパティを持たせる必要がある場合は無視できないメモリ使用量につながる可能性があります。また静的プロパティで持たせているため、モックやスタブを用いたテストが難しくなります。

このようなデメリットがあることを考慮した上で、適切にカプセル化を図ってenumの中でシンプルな分岐処理として表現できるようにしていきたい。

Discussion