2010-12-06 10 views
21

本当に簡単な質問ですが、私は「環境が指示します」という答えを期待しています。しかし、私は人々の考えがコンストラクタやメソッドにパラメータを渡すことに何があるのだろうと思っていました。コンストラクタパラメータとメソッドパラメータ?

私は私の質問のためのコンテキストを試してみて、設定します:

public interface ICopier 
{ 
    void Copy(); 
} 

public class FileCopier : ICopier 
{ 
    String m_source; 
    String m_destiniation; 

    FileCopier(String source_, String destination_) 
    { 
     m_source = source_; 
     m_destiniation = destiniation_; 
    } 

    public void Copy() 
    { 
     File.Copy(m_source, m_destiniation, true); 
    } 
} 

それともFileCopier.Copy()メソッドのパラメータとしてSOURCE_とdestination_を受け入れるべき?

これらのクラスを可能な限り抽象的にしておきたいと思います。

私は現在、削除、名前の変更などのための他のインターフェース/クラスを持っているので、この質問をしています。これを行うための標準を作成したいと思います。

ありがとうございます!

答えて

12

メソッドに渡します。そうすれば、FileCopierを再インスタンス化せずに複数の場所にコピーし、他のパラメータを必要とする可能性のある操作を行うことができます。この場合、メソッドを静的にすることができるので、インスタンス化はまったく必要ありません。これは、C#Fileクラスが動作する方法に気づくでしょう。

+2

私はこのアプローチを行ってきたが必要になりますので、その後、コンストラクタでそれを追加します。これらの2つのビットのデータがコピーに対してのみ意味を持ち、後には意味がないので、メソッドのパラメータとしてsource_とdestination_を渡すことにしました。これはCopy()の多くの実行に適用されるため、 '上書き'フラグなどの状態データにコンストラクタパラメータを使用します。 – adamwtiko

1

すべての使用方法です。

どちらがあなたにとって簡単ですか?

FileCopier f = new FileCopier(sourceFrom,sourceTo); 
f.Copy(); 

または

FileCopier f = new FileCopier(); 
f.Copy(sourceFrom,sourceTo); 

私だけではなく二を好む読みやすいだけでなく、あなたのパスが変更されると、オブジェクトを再作成する必要はありませんので。 ctorにソースを設定することはあまり良い考えではありません。しかし、再び、それは私だけかもしれません。

1

私たちが表示していないソースファイルと宛先ファイルを操作する方法が他にたくさんある場合を除き、static classであり、ファイルパスをクラスレベルの変数として保存しないでください。むしろ、クラスの個々のメソッドのすべては、操作されるファイル(および他の必要な情報または設定)をパラメータとして受け入れる必要があります。これにより、ファイルをコピーするたびにクラスのインスタンスをインスタンス化する必要がなくなります。

FileCopier.Copy(src, dest); 

FileCopier fc = new FileCopier(src, dest); 
fc.Copy(); 

私がここで話しているかの最良の例は、.NET FrameworkのSystem.Math classです。 System.IO.File classもこの方法で動作します(そしてなぜそれを再作成しているのかという疑問が湧きます)。

+0

静的ではないメソッドがあっても、ファイルコピーfuncは静的である必要があります。おそらく、 'メンバー'ファイルをコピーしたパラメータのないオーバーライドが必要です。 – Patrick

+0

最初の例では、 'new FileCopier(src、dest).Copy();を書くことを妨げるものは何もありません。 –

+1

@Patrick:一般的に私はあなたに同意しますが、それはまだクラスの設計に依存します。ファイルをコピーするための標準的なユーティリティクラスではないかもしれないと私には分かりますが、ちょっと変わった実装にはメリットがあります。意図された使用例が2つの特定のファイルに対して一連の拡張操作を実行し、それらのファイルがクラスのインスタンスと密接に結合される理由がある場合、それを静的にする必要はないかもしれません。 –

25

それは依存:)

基本的には、オブジェクト指向のオブジェクトはデータと振る舞いをカプセル化すべきであると述べています。データをコンストラクタパラメータとして渡すとき、これがカプセル化するデータであることを示します。

一方、データをパラメータとして渡すとき、これは何らかの形でオブジェクトに結合されていないデータであることを示します。データコンテキストインタラクション(DCI)に移行すると、多くのオブジェクトがデータよりも動作をカプセル化する傾向がますます高まります。

また、本書では、メソッドパラメータの数を制限して、パラメータを持たないメソッドがすべての最適な設計であるという最終的な結論に導いています。

私は単純なAPIを持つために、コンストラクタパラメータとして渡すことでデータをカプセル化する傾向があります。その後、コマンドオブジェクトのように見えます。

+1

+1を参照してください。 –

+0

私はMarkと完全に同意しますが、文脈を理解することは重要です。理想的なクラスは "IFoo(){void Foo()}"のような最終的な結論に向かってすべてのアプリケーションを設計することはできません。まるでDIを使っているかのように思うと便利だと思います。どのようなあなたの依存性(注射可能/コンストラクタ引数)vsあなたのランタイム値(newables /メソッドargs)ですか? 1つのソースファイルをdestファイルにコピーする必要があるクラスのコンテキストでは、ICopier {void Copy(src、dest);}は "ICopier {void Copy();}"よりも意味があります。 ... 右? :) –

+0

ポイントへの印に同意します。コードは彫刻のようなものです。あなたはその内面の美しさと優雅さを引き出すためにそれを切り刻む。残念なことに、私たちはしばしば、パフォーマンスと効率という他の要因が作用するシナリオにぶつかります。 FileCopierの例では、ソースとデスティネーションの格納は非効率的です。特に、FileCopierは大規模なオブジェクトです。メモリを節約するためにFileCopierインスタンスを新規作成および削除すると、パフォーマンスにも大きな影響があります。 –

5

一般に、クラスに不要な状態を追加することは避けてください。つまり、特定の操作のコンテキストでのみ必要なデータ項目がある場合は、通常、それらをメソッドのローカル変数として使用し、それらをパラメータとして渡すことをお勧めします。

この方法では、メソッド間で共有される不必要な状態が少なくなり、バグの可能性が低くなるため、コードのエラーが発生しにくくなります。

クラスの使用中に値を決して変更しないように強制する場合は、コンストラクタにパラメータを渡す必要があります。

特定のファイルのみをコピーできるFileCopierオブジェクトを作成することは意味がありません。その場合は、メソッドが適切です。

一方、進行状況の追跡、エラー追跡、完了コールバックなどの各コピー操作の状態を管理する必要がある場合は、コンストラクタでパラメータを渡すのが理にかなっていますが、 Copyが複数回呼び出されるのを防ぎます。

1

FileCopierの責任はソースからデスティネーションへファイルをコピーすることであり、実装しているInterfaceを他のヘリウムクラスと一緒に使用できるので、Copy()関数にパラメータを渡すと、より具体的になりますが、現状では、コピー機能を必要とする多くの場所で使用することができます。

1

コンテキストに合わせるクラス内にコピーメソッドしかない場合は、パラメータをメソッドに渡す方が便利です。しかし、それらをコンストラクタに渡すことは、同じオブジェクトを使用して複数の操作を行う必要がある場合に役立ちます。例えば

public class FileCopier : ICopier 
    { 
     String m_source; 
     String m_destiniation; 

     FileCopier(String source_, String destination_) 
     { 
      m_source = source_; 
      m_destiniation = destiniation_; 
     } 

     public void Copy() 
     { 
      File.Copy(m_source, m_destiniation, true); 
     } 

     public void DeleteSource() 
     { 
     } 

     public void DeleteCestination() 
     { 
     } 

    etc... 
    } 
6

アプリケーションがstalessまたはステートフルである場合にも依存します。ステートフルなアーキテクチャでは、コンストラクタにパラメータを渡すことを選択し、そのオブジェクトを保存して、すでに初期化されたインスタンスを複数回呼び出すことができます。ステートレスアプリケーションでは、オブジェクトのインスタンスを作成するたびにオブジェクトの状態を作成する必要があります。これは冗長であるため、これらのパラメータをメソッドに渡して、より明確なインタフェースを選択します。

+0

いい答えです。私はステートレス対ステートフルな観点からこれに決して接近しませんでした。 – adamwtiko

+0

ありがとう!私はたいてい、非常に静かな種類のアプリケーションであるWebサービスアーキテクチャを使用しています – t3mujin

+0

どちらのアプローチがより優れているか、ステートレスかステートフルですか。利点と欠点は何ですか? –

1

あなたのインターフェースについて誰も言及していない奇妙なものICopier

このインターフェイスを見るだけで、メソッド自体の引数を渡します。 これは契約であるため、このインタフェースを実装するオブジェクトに、タスクを完了/実装するための正当な引数を受け入れるように強制する必要があります。

Copy()の実装を求めている場合は、タスクを達成するために必要な値/引数も提供する必要があります。

4

古い質問ですが、多くの人がICopier抽象化の意図を考慮せずに回答しているようです。 Saurabhが記述されているように、copy(String、String)(それに応じてインターフェイスを調整する)を行うと、ICopierの他の実装はこのメソッドの使用に限定されます。

ファイルを送信元から送信先のファイルではなく電子メールのリストに送信するEmailCopierを作成するためにファイルを拡張する必要がある場合はどうすればよいですか?コマンド)

ICopier copier = new EmailCopier(); 
copier.copy(sourceFile, "[email protected],[email protected]"); 

それとも、適切なデータ構造を使用して、コンストラクタでこのすべての情報を入れることができますし、単純なコピー(::あなたは(文字列、文字列)を受け入れるように続けハック方法を書くことができ

ICopier copier = new EmailCopier("sourceFile', aListOfEmails); 
copier.copy(); 

要約すると、インターフェイスの実装のパラメータが大きく異なる場合は、コンストラクタパラメータを単純なコマンドで使用する必要があります。すべての実装が同じ入力で動作している場合、メソッドのパラメータは問題ありません。

2

私は最近、次のルールを見つけました"実装のためにパラメータが使用されている場合、そのパラメータがインタフェースのために使用されている場合はコンストラクタに入れます。

問題は、Copyメソッド上の任意のコメントを持っていないです。

  • それは「宛先から送信元へ写し1ファイル」なら、あなたはについて話すために、あなたは送信元と送信先のパラメータを追加する必要がありますそれインタフェース記述
  • であれば、それだ「コピー何かを上書きする場合」のみごFileCopierの実装は、それが
関連する問題