概要
実践ドメイン駆動設計にて、値オブジェクトの実装方法の1つとして、列挙型の利用が挙げられています。
ただし Java!!
Delphi は Java と違って列挙型に処理を持てない…つらい…
なんてことはないんじゃあないか…? と思い立って書いてみたのが以下のコードです
procedure TMyTest.IsSuccess(ResponseStatus: THttpStatusEnum; ACode: Word);
begin
Assert.IsTrue(ResponseStatus.IsSuccess());
Assert.IsFalse(ResponseStatus.IsFail());
Assert.AreEqual(ResponseStatus.Detail.Code, ACode);
end;
で、ResponseStatus
ですが、列挙型です。
type
THttpStatusEnum = (
Ok200,
Created201,
Accepted202,
NonAuthoritativeInformation203,
NoContent204,
ResetContent205,
PartialContent206,
NotFount404,
InternalServerError500
);
列挙型から! 関数を呼び出す!!
列挙、なんていうくらいですから、分類を持たせると思います。
そこにロジック等々を持たせられると、分類に紐付いたメッセージやコードや条件を整理しやすくなるわけです。
どうかくか
interface
type
PHTTPStatusRec = ^THTTPStatusRec;
THTTPStatusRec = record
private
FCode: Word;
public
property Code: Word read FCode;
end;
type
THttpStatusEnum = (
Ok200,
Created201,
Accepted202,
NonAuthoritativeInformation203,
NoContent204,
ResetContent205,
PartialContent206,
NotFount404,
InternalServerError500
);
THttpStatusEnumHelper = record helper for THttpStatusEnum
private
function GetDetail: PHTTPStatusRec;
public
function IsSuccess(): Boolean;
function IsFail(): Boolean;
property Detail: PHTTPStatusRec read GetDetail;
end;
implementation
const
HTTPStatus: array[THttpStatusEnum] of THTTPStatusRec =
(
(FCode: 200),
(FCode: 201),
(FCode: 202),
(FCode: 203),
(FCode: 204),
(FCode: 205),
(FCode: 206),
(FCode: 404),
(FCode: 500)
);
const
HttpSucessSet = [
Ok200,
Created201,
Accepted202,
NonAuthoritativeInformation203,
NoContent204,
ResetContent205,
PartialContent206
];
HttpErrorByRequest = [
NotFount404
];
HttpErrorByServer = [
InternalServerError500
];
{ THttpStatusEnumHelper }
function THttpStatusEnumHelper.IsFail: Boolean;
begin
Result := (Self in HttpErrorByRequest) or (Self in HttpErrorByServer);
end;
function THttpStatusEnumHelper.IsSuccess: Boolean;
begin
Result := Self in HttpSucessSet;
end;
function THttpStatusEnumHelper.GetDetail: PHTTPStatusRec;
begin
Result := @HTTPStatus[Self];
end;
使っているテクニックは以下です。
- レコード定数
- 列挙型による配列
- アクセス修飾子
- レコードヘルパー
レコード定数
宣言された定数: レコード定数 - RAD Studio
docwiki にも書かれているものですね。
構造体は定数として宣言できます。
docwiki のコードをそのまま引用します
列挙型による配列
これは結構お世話になるものかと思います。
列挙型は配列長の指定につかえるので、分類とそれに対応する文字列の宣言にも、使ってたりします。
アクセス修飾子
type
PHTTPStatusRec = ^THTTPStatusRec;
THTTPStatusRec = record
private
FCode: Word;
public
property Code: Word read FCode;
end;
public
に置いているのは、property
1 つだけの構造体です。
ただ、private
でアクセス可能な範囲はユニットになるので、このファイル内においてはアクセスが可能です。
定数宣言であってもです。
そして、このファイルの外からは読み取り専用となるため、書き換えられることもないです。
クラスヘルパ/レコードヘルパ
クラス ヘルパとレコード ヘルパ(Delphi) - RAD Studio
こいつが罠でしたね。レコードヘルパってかいてあるのに、列挙型でも使えるなんて!
乱用するべからず、とは思っていますが、やっぱり便利。
どんな場面で使うか
HTTP のステータスコードといった、ある程度分類が定まっているものにつかえそう、と思ってます。
あと書いてて思ったのが、ロジックが書きやすく、テストもしやすいです。
列挙型のこれは、どういう分類か、という考え方のもと、別の集合型の定数を書くことで整理できたりするので、ここにいろいろ集約できそう、という気配を感じてます。
おわりに
ということで、DDD でいうところの Value Object の実現方法の1つ、列挙型の Delphi 版でした。