7

大学を卒業したばかりで、結合を減らす必要があるコードに出くわしています。しかし、私はすべての概念を完全には理解していないので、簡単な例を参考にしてください。まず始めに、name という 1 つのフィールドを持つ person クラスを用意しました。そのクラス内にテキストを連結するメソッドがあります。

これはばかげた例であることはわかっています。ほとんどの人は、このような単純な状況で結合を減らすことを考えることはありませんが、コードと概念を一緒に完全に理解するのに役立つ単純な例だけが必要です.

メイン ウィンドウの背後にあるコードに、テキスト ボックスとボタンを配置しました。ウィンドウが読み込まれると、person x name フィールドの現在の値が表示されます。ボタンがクリックされると、x.PersonAddText メソッドが呼び出されます。現在、この例では結合が 8 で計算されています。ボタン クリック イベントは 3、ウィンドウ ロード イベントは 3 です。

この例を使用して、どちらかまたは両方をこれよりも少なくする方法はありますか?

以下はすべての私のコードです:

私の人物クラス:

public class Person
{
    //Fields
    private string name;

    //Properties
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    //Constructors
    public Person()
    {
        name = "joe";
    }

    //Methods
    public string PersonAddText(string text)
    {
        return name += " - " + text;
    }

    //Interfaces (or additional code below here please to aid understanding)
}

私のコードビハインド:

    Person x = new Person();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        txtname.Text = x.Name;
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        txtname.Text = x.PersonAddText(txtname.Text);
        txtname.Text = x.Name;
    }

私の単純な XAML:

<Grid>
    <TextBox Name="txtname" Margin="12,12,12,0" Height="23" VerticalAlignment="Top" />
    <Button Content="Add Text" Margin="12,41,12,0" Name="button1" VerticalAlignment="Top" Click="button1_Click" />
</Grid>

これを説明するインターネット上のチュートリアルを理解するのに非常に苦労しています。私が見たところ、これを行うには 3 つの方法があります (可能であれば、上記のコードを 3 つすべての例に変換するとよいでしょう)。

  • サービスロケーター
  • 依存性注入
  • 制御の反転 (IoC)

私が読んだ内容を説明する記事は優れていますが、データベース接続文字列で VB と ASP.Net を使用しているため、例は私には関係ありませんこれは私が必要としているものとは正反対であり、概念を学びながらコードを翻訳する方法を考えたくないし、それを関連するものに適用する方法についても考えたくありません。例は良いものですが、多すぎます。追加の助けをいただければ幸いです。

編集履歴: スペルを修正しました。私の質問を明確にするために以下を追加しました:

カップリングと凝集の背後にある理論と、一方を減らして他方を増やす必要がある理由を理解しています。しかし、大学で例をコーディングする必要はありませんでした。また、大学ではカバーされていませんが、インターフェイスは理解しています。ただし、結合を減らすためにそれらを使用する方法がわかりません。

上記で参照した記事へのリンクを追加しました。

編集2:これまでのところ、私が得たものは次のとおりです。

public interface IPerson 
{ 
    string Name { get; set; } 
    string PersonAddText(string text); 
} 

public class Person : IPerson 
{
    //The code from the person class above
}

メインウィンドウのコードビハインドでこれを使用するにはどうすればよいですか? 交換した方がいいと思います

Person x = new Person();

IPerson x = new Person(); 

これは正しいですか、もしそうなら、私がしなければならないことは他にありますか。私が尋ねる理由は、Visual Studio によって報告されたコード カップリングの数値が減少していないことをまだ確認していないためです (実際には、メイン ウィンドウのコード ビハインドで 1 増加します)。

4

3 に答える 3

3

編集

私の答えが少し役に立ってよかったです。もう少し更新させてください。質問を直接の回答として使用するには、変更する必要があるのは、次のフィールド宣言だけです。

Person x = new Person();

IPerson x = new Person();

コード ビハインドは、インターフェイスで指定されたプロパティとメソッドを認識するようになり、後でスワップ アウトできるnew Person()ため、結合がはるかに少なくなります。new Student()オブジェクトがインターフェイスを実装している限り。コード ビハインドは、必要な変更を行わなくても機能するはずです。

サイドノート

個人の遅延読み込みを検討xし、より認識しやすい名前のプロパティを使用することをお勧めします。NBこれはあなたの質問には答えませんが、単なる提案です。:)

private IPerson _CurrentPerson = null;
private IPerson CurrentPerson
{
    get
    {
        if (this._CurrentPerson == null)
        {
            this._CurrentPerson = new Person();
        }
        return this._CurrentPerson
    }
    set
    {
        this._CurrentPerson = value;
    }
}

デカップリングとは、2 つ以上のコード ブロックが互いに依存してはならない場合です。制御の反転は、オブジェクトの結合が実行時にバインドされる場合に発生します。これにより、オブジェクトとそのインスタンスの柔軟性が大幅に向上し、結合が少なくなります。制御の反転は、インターフェイスと組み合わせて使用​​するのが最適です。インターフェースは、それClassAが行うことMethodXと持つことを定義しますPropertyY。私たちの主なオブジェクトは、実行時にどのオブジェクトが返されるかを気にしません。log はインターフェースを満たせるので、満足です。

上記の例では、おそらく次のように、個人クラスをインターフェースしたいと思うでしょう:

public interface IPerson
{
    string Name { get; set; }
    string PersonAddText(string text);
}

public class Person : IPerson
{
    // your code here
}

次に、メイン メソッド呼び出し内で、オブジェクトを明示的に使用する代わりにPerson、インターフェイスを実装するオブジェクトのインスタンスを使用しますIPerson。インターフェイスとオブジェクトの「フック」は、依存関係の設定に役立つさまざまなライブラリによって実現できます。私の経験では、StructureMapMicrosoft の Enterprise Libraryを使用しました。セットアップが少し面倒かもしれませんが、一度セットアップすると、次のようなことができるようになります...

public void MainMethod_InInterfaceLayer()
{
    // container is an instance of UnityContainer
    Person newPerson = container.Resolve<IPerson>();
}

これが完全な答えではないことはわかっていますが、少し役立つことを願っています。:)

于 2012-05-09T11:11:58.387 に答える
2

インターフェイスIPersonといくつかの実装(Person、など)がありStudentTeacher単に操作する必要のあるコードがあるとしますIPerson

持っている:

IPerson x = new Person();

Person背後にあるコードでは、それをクラスに強力に結合します。

制御の反転は、クラスの内部を作成するのではなく、外部から依存関係を取得することによって機能します。

これは通常、依存性注入を使用して実現されIPersonます。つまり、クラスが直接作成するのではなく、クラスに渡されます。これを行うには、インスタンスをコンストラクターに渡す(コンストラクターインジェクション)か、プロパティとして渡す(プロパティインジェクション)。

サービスロケーターは、依存関係をハードコーディングせずに取得するもう1つの方法です。パターンは、タイプ/インターフェイスのインスタンスを「検索」します。

クラスに依存関係を注入する方法の例:

public class MyClass
{
  IPerson person;

  public MyClass(IPerson p)
  {
    person = p; // injected an instance of IPerson to MyClass
  }

  // can now use person in any method of the class, or pass it around:

  public void MyMethod()
  {
     string name = person.Name;
  }
}
于 2012-05-09T11:15:25.887 に答える
0

データベースから自分自身をロードし、変更され、彼または彼女が亡くなったときに電子メールを送信できるPersonクラスがあるとします。

class Person 
{
    ...
    void LoadUsingId(int id);
    void HaveDiedWillMail();
    void SetFirstName(string name);
    ...
}

ここでわかるのは、この人が実際に3つのことをしているということです(少なくとも!)。

データベースと通信して自身をロードする方法を知っています。それは電子メールを送る方法を知っています。それは自分自身を変えることができます。

理論的には、どのコードも、実践されていない場合でも、1つのことだけを担当する必要があります。これらのコンポーネント間の結合を減らすには、コンポーネントを引き離す必要があります。それらを切り離して、独立して動作できるようにします。

class Person 
{
    ...
    void LoadUsingId(PersonRepository person);
    void HaveDiedWillMail(IMailer mailer);
    void SetFirstName(string name);
    ...
}

この不自然な例では、Personはデータベースから何かをロードする方法を知りません。-loading-があなたも切り離すべきものであるという事実を無視します。Person.HaveDiedWillMail特定のメーラーを使用するように指示したため、メール送信も分離されました( IMailer mailer)。

依存性注入、サービスコンテナ、およびそのようなテクノロジーは、Personが機能するために必要な/必要なコンポーネントを自動的に検出します。デカップリングの上に追加のレイヤーを配置して、すべての個別のパーツを簡単に配線できるようにします。

于 2012-05-09T11:15:44.197 に答える