MENU

プリミティブな型をラップする

以前、下記記事にて「int, string等で扱われる変数の恐ろしさ」について記載した。

あわせて読みたい
私にとってのリファクタリングとは ここまでコードリファクタリングについて4本の記事を挙げてきたが、なぜ私がコードリファクタリングについて考えているのかを記載する。 私が入社した会社のプログラム...

その改善策として有効な方法は「プリミティブな型をラップ」したクラスを作成することだ。

目次

プリミティブ型とは

そもそもプリミティブ型とはなんだろうか。Wikipediaの説明を見る。

プリミティブ型またはプリミティブデータ型: primitive data type)は、データ型の分類用語であり、データ型の中で最も基本的なものを指している。基本データ型(basic data type)とも言われる[1]。直訳して原始型と呼ばれることもある。1

つまり、プログラミング言語に最初から組み込まれている型であり、C#では int, double, bool, char, string などが該当する。

プリミティブ型はそのまま使うことでシンプルにプログラムを書けるが、適切に管理しないとバグの温床になることもある。

プリミティブ型をそのまま扱う問題点

次のコードを見てほしい。

// 部屋の高さ(m)
double ceilingHeight = 2.1;
// 棚の高さ(mm)
double shelfHeight = 2000;
if(ceilingHeight > shelfHeight)
{
    Console.WriteLine("入らない!");
} 
else
{
    Console.WriteLine("入ります!");
}

このプログラムでは、ceilingHeight はメートル単位なのに対し、shelfHeight はミリメートル単位になっているため、意図しない結果が出てしまう。

このような問題点がある:

  • コードが大規模になると、ミスを見つけにくい
  • 異なる単位が混在するとバグが発生しやすい
  • 型の誤用が起こると、意図しない計算結果が出る

プリミティブ型をラップする

この問題を防ぐために、プリミティブ型をラップするクラスを作成する。

public sealed record Length
{
    private readonly double _value;
    private Length(double value)
    {
        _value = value;
    }
    
    public static Length CreateMeter(double meter)
    {
        return new Length(meter * 1000);
    }
    public static Length CreateMm(double mm)
    {
        return new Length(mm);
    }
    
    public static bool operator >(Length left, Length right)
    {
        return left._value > right._value;
    }
    public static bool operator <(Length left, Length right)
    {
        return !(left > right);
    }
}

この Length クラスを使うことで、単位の不一致によるミスを防げる。

// 部屋の高さ(m)
var ceilingHeight = Length.CreateMeter(2.1);
// 棚の高さ(mm)
var shelfHeight = Length.CreateMm(2000);
if(ceilingHeight > shelfHeight){
	Console.WriteLine("入らない!");
} 
else{
	Console.WriteLine("入ります!");
}

このようにすることで、Length クラスが単位の違いを吸収し、間違いを未然に防げる。

プリミティブ型をラップすることによるメリット

  • 型安全性が向上する:異なる単位のデータを誤って比較することがなくなる。
  • コードの可読性が向上するLength クラスを使うことで、何の値を扱っているかが明確になる。
  • 拡張性が高まる:メートル、ミリメートル以外の単位(センチメートルなど)にも簡単に対応できる。

プリミティブ型をラップすることによるデメリット

  • クラスを定義する手間が増える:小規模なプログラムではオーバーヘッドになり得る。
  • パフォーマンスに影響する可能性がある:値型(struct)ではなく参照型(class, record)を使用すると、メモリ使用量が増える。
  • 柔軟性が下がる:数値の単純な計算が、都度クラスのメソッドを介する必要がある。

まとめ

プリミティブ型をそのまま使うと、意図しないバグを生みやすい。特に、異なる単位のデータを比較する際には、単位の不一致が起こりやすい。

この問題を回避するためには、プリミティブ型をラップするクラスを作成し、単位変換を明示的に行うことが有効である。

ただし、ラップすることでコードの記述量が増えたり、パフォーマンスに影響が出たりする可能性もあるため、プロジェクトの規模や要件に応じて適用を検討すべきである。

プリミティブ型の取り扱いに慎重になり、より安全で保守性の高いコードを目指していこう。

参考書籍(PR)

プリミティブ型を適切に扱い、より安全でメンテナンスしやすいコードを書くために、以下の書籍をおすすめする。

リファクタリング: 既存のコードを安全に改善する
Clean Code アジャイルソフトウェア達人の技
ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本

これらの書籍を参考にしながら、安全で理解しやすいコードを目指そう!

  1. プリミティブ型 – Wikipedia ↩︎
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次