仕様書の表をそのまま書くenumテーブルパタン

最近のenumはただ値を列挙するだけでなく、フィールドやメソッドを持てることが多いです
そうゆう機能を最大限にいかす方法としてenumテーブルパタンを紹介します

たとえば各商品の原価に対して値段を決める仕様があるとします 仕様書はこんな感じ

商品と値段の仕様

商品ID 商品名 原価率 課税
P001 りんご 30% 課税
P002 みかん 50% 課税
P003 笑顔 100% 非課税

それぞれの商品について原価から値段を算出するプログラムを書きます

if文地獄な書き方

int createPrice(String productId, int cost) {
  if(productId.equals("P001")) {
    return ((int)(cost * 100 / 30)) * 108 / 100;
  }
  if(productId.equals("P002")) {
    return ((int)(cost * 100 / 50)) * 108 / 100;
  }
  if(productId.equals("P003")) {
    return cost
  }
  throw new RuntimeException(“product not found”);
}

商品が増えたら辛いですね
仕様書通りに実装できているかチェックするのも大変そう

enumテーブルパタンで書く

enumを使って仕様書をできるだけそのまま再現します

enum Product {
    apple("P001", "りんご", 原価率30per, 課税),
    orange("P002", "オレンジ", 原価率50per, 課税),
    smile("P003", "スマイル", 原価率100per, 非課税);

    private final String productId;
    private final String name;
    private final CostRate costRate;
    private final Tax tax;

    Product(String productId, String name, CostRate costRate, Tax tax) {
        this.productId = productId;
        this.name = name;
        this.costRate = costRate;
        this.tax = tax;
    }

    int price(int cost) {
        return Stream.of(cost)
                .map(costRate::calc)
                .map(tax::calc)
                .findFirst()
                .get();
    }
}

enum CostRate {
    原価率30per(30),
    原価率50per(50),
    原価率100per(100);
    private final int p;

    CostRate(int p) {
        this.p = p;
    }

    int calc(int v) {
        return v * 100 / p;
    }
}

enum Tax {
    課税(108),
    非課税(100);
    private final int p;
    Tax(int p) {
        this.p = p;
    }
    int calc(int v) {
        return v * p / 100;
    }
}

仕様書の表の見た目をそのままにProductクラスを作れました
これならコードレビューも楽だし、ジェネレータを作って仕様書から直接enumを生成することもできそうです

まとめ

enumの特性を活用したenumテーブルパタンを使うと、仕様書の表をそのままコードにできる