2011-09-20 13 views
5

私は多くの家庭プロジェクトでF#に徐々に切り替えていますが、完全なアプリケーションを結びつける方法、特にクロスカッティングに関する懸念については少しぼやけています。F#アプリケーション構造ログ/リポジトリ

C#では、ログオンしたい場合は、依存関係注入を使用してILoggerを各クラスに渡してから、コードから素敵に簡単に呼び出すことができます。私は自分のテストで、モックを渡して検証する特定の状況のログが書かれていることを確認できます。

のF#では
public class MyClass 
{ 
    readonly ILogger _logger; 
    public MyClass(ILogger logger) 
    { 
     _logger = logger; 
    } 

    public int Divide(int x, int y) 
    { 
     if(y == 0) 
     { 
      _logger.Warn("y was 0"); 
      return 0; 
     } 
     return x/y; 
    } 
} 

することは、私はより多くのモジュールを使用していますので、私は、私はちょうどそれを開いて、そこからログ機能を使用することができ、モジュールと呼ばれるログを持っていた場合は、上記の今

module Stuff 

let divde x y = 
    match y with 
    | 0 -> 0 
    | _ -> x/y 

になるでしょうyが0の場合は、単体テストのためにどのように注入するのですか?

私は各機能にログ機能(文字列 - >単位)を持たせることができましたが、部分アプリケーションを使用して接続することができましたが、実際の呼び出しを内部でラップする新しい関数を作成するロギングコール特定のパターンやF#のビットが私はそれを行うことができます行方不明だ? (私はkprintf関数を見たことがありますが、完全なアプリケーションの具体的な実装を使っていながら、さまざまなテストシナリオで関数をどのように指定するかはまだ分かりません)

同様に、データを取得しましたか?いくつかのクラスをインスタンス化し、CRUD関数を設定する必要がありますか、または開いているモジュールを挿入する方法がありますか(#define以外)

+0

のhttpあなたのロギング用のC#から、あなたが知っているのと同じ技術を使用できるようにする必要があり、最初のC#

module stuff type MyClass(logger:#Ilogger) = member x.Divide a b = if b=0 then logger.Warn("y was 0") 0 else x/y 

に似ているF#で自分のC#コードの実装です:/ /stackoverflow.com/questions/2003487/architectural-thinking-in-functional-languages http://stackoverflow.com/questions/192090/how-do-you-design-a-functional-program –

答えて

2

これは基本的な答えです。まず、クラスとモジュールを交換可能と考えているようです。クラスはデータをカプセル化します。その意味でレコードとDUに似ています。一方、モジュールは機能をカプセル化します(静的クラスにコンパイルされます)。だから、私はすでにあなたのオプションを述べたと思います:部分関数アプリケーション、関数としてデータを渡す、または...依存関係注入。あなたの特定の場合は、あなたが持っているものを保つのが一番簡単です。

別の方法として、プリプロセッサディレクティブを使用して異なるモジュールを組み込む方法があります。

#if TESTING 
open LogA 
#else 
open LogB 
#endif 

DIは必ずしも機能的な言語ではあまり適していません。指摘する価値はあるが、F#では、C#よりも定義と実行のインターフェースがさらに簡単になります。

+0

hmmm、だからF#クラスだけのレコードとDUを持っていなかった場合、通常は結果ではなく(少なくともデバッグで)操作についてログに記録したいので、ロギングはモジュールで行わなければなりません操作のこれは、DIがウィンドウの外にあるので、部分的なアプリケーションがすべて残っていることを意味します。万が一機能アーキテクチャについての読書をお勧めしますか?あまりにも長い間、私はこの種のことがすでに解決されていると確信していますが、私が見た本はすべて「大」よりも「小さい」に集中しています。 – Dylan

+0

私はしたいと思います。私はこれも早い段階で苦労していることを覚えています。私はF#で "大きな"アーキテクチャが根本的に異なると予想しました。一部の関数型言語では、モジュールをパラメータ化できます。残念ながら、F#はそうではありません。 OOはまだ "大規模な"良いアプローチです。私はその質問が数回行われたことを知っています。クイック検索が表示されました:http://stackoverflow.com/questions/2003487/architectural-thinking-in-functional-languages他にもあるかもしれない。 – Daniel

+0

そのリンクをありがとう、私は以前に検索を行ったが、実際にガイダンスを与えたものは何も見つかりませんでした。私はあなたが部分的なアプリケーションでは正しいと思いますが、私は、依存関係がホスティングアプリケーションによって配線されるようになる前に、カプセル化のレベルを上げなければならないと思います。 – Dylan

3

実行時にロガーを変更する必要がない場合は、コンパイラ・ディレクティブまたは#ifを使用してロガーの2つの実装(Danielが示唆するように)を選択するのがおそらく最も簡単で簡単な方法です。

機能面では、依存性注入とは、すべてのコードをロギング機能でパラメータ化することと同じ意味です。悪い点は、どこにでも関数を伝播する必要があることです(コードがちょっと乱雑になります)。また、グローバル変数をモジュール内に作成し、それを​​インタフェースのインスタンスに設定することもできます。これは、F#の場合はかなり受け入れられるソリューションだと思います。なぜなら、この変数をいくつかの場所でのみ変更する必要があるからです。

別の(もっと純粋な)別の方法は、ログ用に(別名モナド)というワークフローを定義することです。これは、F#ですべてのコードを記述する場合にのみ適しています。この例は、私の本の第12章で説明されています。available as a free sampleです。次に、あなたは次のようなものを書くことができます:

let write(s) = log { 
    do! logMessage("writing: " + s) 
    Console.Write(s) } 

let read() = log { 
    do! logMessage("reading") 
    return Console.ReadLine() } 

let testIt() = log { 
    do! logMessage("starting") 
    do! write("Enter name: ") 
    let! name = read() 
    return "Hello " + name + "!" } 

このアプローチの良い点は、素晴らしい機能テクニックです。 Log<'TResult>を返す関数は、副作用の記録だけでなく、価値も提供するので、結果を比較することができるので、テストコードは簡単でなければなりません!しかし、それは残念なことかもしれません。なぜなら、log { .. }ブロックのログを使用するすべての計算をラップする必要があるからです。ここで

+0

ありがとうTomas、 私はまだ変更が邪悪であるということに屈しています。私のC#コードでは、常に依存関係を読み込み専用にしています。コード内に変更可能なロガーを作成すると、偶発的な再割り当てからそれを保護する簡単な方法はないと思います。私は別のコメントで言及したように、アプリケーションの上位レベル(派生した機能性)は下位のモジュールにアクセスしないと思います。 – Dylan

+0

@Dylan - はい、モジュールの宣言は順序に依存しますので、ロギングモジュールを先に実行する必要があります。一般に、可変性は悪い(F#で)のは事実です。しかし、ロガーを再捕らえる必要がない場合は、最も簡単なオプションです。 –

0

が、これはあなたが

+0

ありがとう、私はむしろこのタイプのアプローチのためにC#を使用したいと思います。私は実際にはっきりさせませんでしたが、クラスなしでレコードと関数定義だけを使ってこのアプローチを行う方法の方が多くありました。 – Dylan

+0

マイナーなことではありません。この場合、##ILoggerタイプは必要ありません。メソッドまたはコンストラクタを呼び出すときに自動的にキャストを挿入します。ここではハッシュ型を使用するのはちょっと変わったようです - ここでは必要ないクラス全体をジェネリック(ロガー型よりもパラメータ化)にすることさえあると思います。 –

+0

@Tomas - コンパイラを使って自分のコードをチェックするのをやらなくても –

関連する問題