これは副作用であるため、データベース操作は関数型プログラミングの対象ドメインではありません。 FPの主な価値は、可能であれば純粋な関数を使うことにあります。
しかし、OOPにはこれと並行して、データベースリソースをパラメータとして取ることが適切な方法であると示唆されることがあります。 SOLIDの原則を使用してOOPのDB実装を検討してください。 Interface Segregation Principleのため、DBメソッドごとのインターフェイスとインターフェイスごとに少なくとも1つの実装クラスになります。
l
次に、ユースケースを実行するために、DB操作のセット全体ではなく、必要な依存関係のみを渡します。 (ISaveRegistration
が存在し、上記のように定義されていると仮定します)。どこかでこのコードが呼び出された場所の上
// C#
public async Task Register(
IGetRegistrations a,
ISaveRegistration b,
RegisterRequest requested
)
{
var registrations = await a.GetRegistrations(requested.Date);
// examine existing registrations and determine request is valid
// throw an exception if not?
...
return await b.SaveRegistration(...);
}
、あなたは、これらのインタフェースの実装まで新に持っているとDbResource
とそれらを提供。
var a = new GetRegistrationsImpl(db);
var b = new SaveRegistrationImpl(db);
...
return await Register(a, b, request);
注:あなたは、いくつかの決まり文句を避けるためにしようとするためにここにDIフレームワークを使用することができます。しかし、私はそれがピーターからポールを借りて借りていることがわかります。あなたは、DIフレームワークを学ばなくても、自分自身の依存関係を配線するときと同じように、DIフレームワークをどのように動作させるかを決めることができます。それは新しいチームメンバーが学ばなければならない別の技術です。
FPでは、DBリソースをパラメータとして使用する関数を定義するだけで同じことができます。インタフェースを実装しているクラスにラップするのではなく、直接関数を渡すことができます。
// F#
let getRegistrations (DbResource : db) (day : DateTime) =
...
let saveRegistration (DbResource : db) ... =
...
ユースケース機能:
// F#
let register fGet fSave request =
async {
let! registrations = fGet request.Date
// call your business logic here
...
do! fSave ...
}
は、その後、あなたがこのような何かを行う可能性があり、それを呼び出す:
register (getRegistrations db) (saveRegistration db) request
ここdb
の部分的なアプリケーションは、注射をコンストラクタに似ています。あなたの "損失"が複数の機能に渡ることは、各DB操作のためのインタフェース+実装を定義する必要がないという節約と比べて最小限です。
機能 - 第一言語であるにもかかわらず、上記は原則的にOO/SOLIDと同じです...コードの行数が少なくて済みます。機能領域への一歩を進めるためには、ビジネスロジックの副作用をなくす必要があります。副作用には、現在時刻、ランダム、例外のスロー、データベース操作、HTTP API呼び出しなどがあります。
F#では副作用を宣言する必要はないため、副作用を使用しない場所を指定します。私の場合、ユースケースレベル(上記のregister
関数)が副作用の最後の場所です。それより低いビジネスロジックがあれば、私はそれらをユースケースにプッシュします。それは、それを行う学習プロセスですので、最初は不可能と思われる場合は落胆しないでください。今はあなたが持っていることをして、あなたが行くにつれて学びます。
私はa postを持っています。これは、FPの利点とその入手方法に関する正しい期待を設定しようとしています。