3

いくつかのユーザーコントロールがあり、各ユーザーコントロールがタブ項目内、ウィンドウ内にあるとします。

たとえば、これが食品収集アプリケーションであるとしましょう。次に、果物、野菜、スナックのタブがあります。各タブには、その主題の食品のリストが表示され、ユーザーは各セクションで食品を追加、削除、変更できます。食品は個別のテキストファイル、つまり Fruit.txt、Vegetable.txt、Snack.txt に保存されます。

実際のテキスト ファイルは次のようになります (vegetable.txt)。

Name        Carbs    Fat
Eggplant    2        1.1
Cucumber    3        0.5
etc

これは大きなリストであり、すべての野菜をリストに引き出す load メソッドがあります。

私が持っている質問は、この loadVegetables メソッドがコード ビハインド ファイルにあるということです。ReviewAllFood、AddVegetable などの別の画面と、フルーツとスナック。

これは設計上の問題です。このコードを繰り返さないようにどのように設定したのか疑問に思っています。load メソッドがある場所に、VegetableManager (または何か) クラスを配置することもできますが、これは実際にはコードの繰り返しが少ないことを意味するのでしょうか? 次に、各画面で、VegetableManager のオブジェクトを作成し、とにかくその load メソッドを呼び出す必要があります。したがって、効率に関してはそれほど良くないと思いますが、より良い設計を実現しています。

ここで何かが足りないと思います。結束と結合を研究してからしばらく経ちましたが、現在、これらの概念について混乱していると思います。誰かがこの状況の設計を提案し、なぜそれを選んだのか、そしてなぜ私が現在行っている方法よりも優れているのかを説明していただければ幸いです.

読んでくれてありがとう。

4

4 に答える 4

3

load メソッドがある場所に、VegetableManager (または何か) クラスを配置することもできますが、これは実際にはコードの繰り返しが少ないことを意味するのでしょうか? 次に、各画面で、VegetableManager のオブジェクトを作成し、とにかくその load メソッドを呼び出す必要があります。

これを行うポイントは、効率 (つまりパフォーマンス) ではありません。ポイントは、そのデータのロードの詳細を単一の分離されたオブジェクトにカプセル化することです。たとえば、サイトが非常に大きくなり、スケーラビリティとパフォーマンスのためにデータ ストレージをデータベースに移動することにしたとします。説明した既存のコードでは、各ユーザー コントロールまたはページを調べて、load メソッドのロジックを変更する必要があります。せいぜいこれは苦痛であり、最悪の場合、一部を見逃したり、誤ってコピーアンドペーストしたりします. ロジックが専用のオブジェクトにカプセル化されている場合、その唯一の責任はどこかからデータをロードする方法を知ることであり、変更を行う必要があるのは 1 回だけです。

ユーザーコントロールの分離コード:

protected void Page_Load(object sender, EventArgs e) {
  var veggieManager = new VegetableManager();
  VeggieListControl.DataSource = veggieManager.GetAll();
  VeggieListControl.DataBind();
}

野菜マネージャー.cs:

public class VegetableManager {
  private static Collection<Vegetable> _veggies;
  private static object _veggieLock;

  public ReadOnlyCollection<Vegetable> GetAll() {
    if (_veggies == null) {
      lock(_veggieLock) { //synchronize access to shared data
        if (_veggies == null) { // double-checked lock
          // logic to load the data into _veggies
        }
      }
    }

    return new ReadOnlyCollection(_veggies);
  }

  public void Add(Vegetable veggie) {
    GetAll(); // call this to ensure that the data is loaded into _veggies
    lock(_veggieLock) { //synchronize access to shared data
      _veggies.Add(veggie);
      // logic to write out the updated list of _veggies to the file
    }
  }
}

_veggiesisであるためstatic、複数の呼び出し元が をインスタンス化するという事実にもかかわらず、メモリには野菜のコレクションが 1 つしかありませんVegetableManager。ただし、静的であるため、マルチスレッド アプリケーション (Web サイトなど) を使用している場合は、すべてのスレッドでそのフィールドへのアクセスを同期する必要があります (したがってlocks)。

これは、優れたオブジェクト指向という点では氷山の一角です。UncleBob の SOLID の原則Domain-Driven Design (無料の電子書籍)を熟読することをお勧めします。

はい、何かを繰り返していますが、繰り返しているのはメソッド呼び出しだけであり、繰り返しても問題ありません。DRY は、「論理」コード、つまり意思決定とアルゴリズムの重複を軽減することを意味します。単純なメソッド呼び出しはこれに該当しません。ただし、必要に応じて、ロジックを基本クラスに統合して、これを行うことで、ユーザーコントロールが野菜マネージャーについて知る必要がないように効果的に分離できますが、これはオブジェクト指向のやり過ぎ、または OOO だと思います:-)

public abstract class FoodUserControl : UserControl {
  protected List<Vegetable> GetVeggies() {
    return new VegetableManager().GetAll();
  }
}

次に、実際のコントロールは、UserControl からではなく、これから派生します。

アップデート

イーガーローディングのVegetableManager.cs:

public class VegetableManager {
  private static Collection<Vegetable> _veggies;
  private static object _veggieLock;

  static VegetableManager() {
    // logic to load veggies from file
  }

  public ReadOnlyCollection<Vegetable> GetAll() {
    return new ReadOnlyCollection(_veggies);
  }

  public void Add(Vegetable veggie) {
    lock(_veggieLock) { //synchronize access to shared data
      _veggies.Add(veggie);
      // logic to write out the updated list of _veggies to the file
    }
  }
}

この熱心な読み込みバージョンでは、コンストラクターの読み込みコードの周りで二重チェックのロックを行う必要がないことに注意してください。また、このコードはフィールドを初期化するため、ロード コードがstaticコンストラクター内にあることに注意してstaticください (そうしないと、すべての構築でファイルからデータを同じ共有staticフィールドに再ロードすることになります)。野菜は熱心に読み込まれるため、GetAll または Add で読み込む必要はありません。

于 2010-02-18T00:33:38.747 に答える
2

ファイルを読むときに、野菜 (またはロードしている野菜) を一度取り出すことをお勧めします。次に、それらを基になるデータ モデルに格納します。リストと、必要なその他のコントロールを基になるデータ モデルにバインドできます。データは 1 回読み込まれますが、さまざまなビューで表示できます。

編集: コードの追加

List<T> loadObjects(File file, ILineConversionStrategy strategy) {
   // read eaqch line of the file
   // for each line
   T object = strategy.readLine(line);
   list.add(object);
   return listOfObjects;
}

EDIT 2: データモデル

class FoodModel {
   List<Vegetable> getVegetables();
   List<Fruit> getFruit();
   // etc
}
于 2010-02-18T00:10:54.217 に答える
0
    public interface IEatable {}

    class Vegitable : IEatable 
    { string Name { get; set; } }
    class Fruit : IEatable 
    { string Name { get; set; } }

    public interface IEatableManager
    {
        List<Vegitables> LoadEatables(string filePath);
    }
    public class VetabaleManager : IEatableManager
    {
        #region IEatableManagerMembers    
        public List<Vegitable> LoadVegs(string filePath)
        {
            throw new NotImplementedException();
        }    
        #endregion
    }
    .
    .
    .

上記のようなデザインを使用するには、考慮すべきことがいくつかあります。

そして必読:

于 2010-02-18T00:33:17.680 に答える
0

これにはリポジトリパターンを使用します。まず、各テキスト ファイルからオブジェクトを取得するメソッドを含む 1 つのクラスを作成します。

public class FoodRepository
{
    public IList<Vegetable> GetVegetables() { ... }
    public IList<Fruit> GetFruit() { ... }
    // etc.
}

このクラスは、食品が実際にテキスト ファイルに格納されていることを認識しているアプリケーション内の唯一のクラスである必要があります。

それが機能するようになったら、パフォーマンスを向上させるために、頻繁に使用されるデータをキャッシュすることを検討することをお勧めします。

于 2010-02-18T00:34:11.657 に答える