2

1 つまたは複数のリストを保持するクラスがある場合、他のクラスがそれらのリストを (getter を使用して) フェッチできるようにする方がよいでしょうか? またはdoXyzList/eachXyzList、そのリストの型メソッドを実装し、関数を渡し、そのオブジェクトに含まれるリストの各要素でその関数を呼び出すには?

私はこれを大量に行うプログラムを書きましたが、これらすべてのリストを渡すのが嫌いでした.classに含まれるリストを返すためAにクラス内のメソッドを呼び出すクラス内のメソッドを使用することもありました。が 1つまたは複数含まれています。BCBCC

(この質問は、ルビーやスモールトークなどの動的に型付けされたオブジェクト指向言語に関するものであることに注意してください)

元。(それは私のプログラムで出てきました):

Personスケジューリング設定を含むクラスschedulerと、それらにアクセスする必要があるクラス。

4

6 に答える 6

4

答えは 1 つではありません。設計とは、優先順位、トレードオフ、妥協点をうまく調整して、状況に応じて適切に機能するものに到達することです。ファンクター、アクセサー、および完全なカプセル化を使用することの相対的なメリットとデメリットについて簡単に説明します。

ファンクタ

ファンクターを使用すると便利で、ボイラープレートの繰り返しを回避できます。これにより、リスト内の各項目に対して実行しているものと、それを実行したときを明確に区別することもできます。for-each ループでは、ほとんどの場合、この 2 つが結合されます。ファンクターが機能しないのは、同じオブジェクトまたは複数のオブジェクトから複数のリストに対して操作を実行する必要がある場合、またはリストのいくつかの要素のみが必要な場合です。ファンクターを使用すると実行順序が制限されます。アイテムは、プロバイダーによって反復される順序で使用する必要があります。ファンクタには制御がありません。これは祝福でもあり、呪いでもあります。

Person、スケジューリング設定、およびスケジューラの例では、スケジューラは可能なスケジュール時間の外部イテレータを提供できます。

   schedules = scheduler.schedules(person.getSchedulePreferred())

getSchedulePreferred() は、利用可能なすべてのスケジュールから、特定の人が好むスケジュールを選択する述語を返します。

すべてのスケジュールを反復することは、これを実装する最も効率的な方法ではない場合があります。たとえば、6 月のスケジュールだけが必要な場合、その年の残りのすべてのスケジュールが無駄に繰り返されます。

アクセサー

クラスに固有ではない機能を実装する場合、gtters を介してリストを使用できるようにすることは有益です。たとえば、2 つの注文が与えられた場合、それらに共通する項目を見つけます。これは、リストが外部トラバーサルのゲッターとして提供されている場合は実装が簡単で、リストが既知の順序で提供されている場合 (たとえば、 Order にgetSortedItems()メソッドがある場合) は非常に簡単です。多くの言語ではリストの可変性を管理するのが複雑です。ミューテーション (C++ の const など) を無効にするか、不変のラッパーでリストをラップする直接サポートがあります。

たとえば、ユーザーはスケジュール設定のリストを公開できます。これは、スケジューラによって直接使用されます。スケジューラーには、プリファレンスがどのように適用されるかについて「スマート」になる機会があります。たとえば、データベースへのクエリを作成して、個人のプリファレンスに基づいて一致するスケジュールを取得できます。

カプセル化

3 番目の選択肢は、外部アクセスが必要かどうかを質問することです。オブジェクトがすべてプロパティであり、動作がないというのは、貧血ドメイン モデルの 1 つの症状です。ただし、このアンチパターンを回避するためだけに動作をドメイン オブジェクトに入れようとしないでください。動作は、そのオブジェクトの責任の自然な部分でなければなりません。

これはここには当てはまらないと思います。担当者、スケジューラ、およびスケジューリングの設定は、明らかに異なる役割を果たし、明確な責任を負っています。別のエンティティからデータを計算しようとするメソッドを 1 つのエンティティに追加すると、不要な密結合になります。

概要

この特定のケースでは、ファンクターを介して「強制的に供給」されるのではなく、スケジューラーがスケジュール設定の使用方法をより詳細に制御できるため、私の好みはゲッターです。

于 2010-06-08T19:18:39.503 に答える
3

どちらもしない方がいいです。これらのリストをカプセル化し、可能であれば、代わりに操作自体をクラス内に移動します。doSomeOperation()次に、タイプの内部データ構造を公開せずに、内部で必要な方法で反復する呼び出しを実行します。

たとえば、通常は次のように設計することをお勧めします。

public class ShoppingCart {
   private final List<CartItem> items;
   public double getTotal() {
      double total = 0;
      for ( CartItem item : items ) {
         total += item.getPrice() * item.getQuantity();
      }
      return total;
   }
}

getTotalShoppingCartの外部に作成するアイテムのリストを公開するよりも。

それが不可能であるか、非常に非現実的である場合は、少なくともそれらのリストの変更不可能なビューのみを提供してください。

于 2010-06-08T14:00:11.673 に答える
0

あなたの質問は:

リストを反復処理するためのパターンですか

「イテレータ」という単純なパターンがあると思いますよね?

このようなもの:(Javaの例)

public class ListHolder<T>
{
    private List<T> list = new ArrayList<T>();

    public Iterator<T> newIterator()
    {
        return new Iterator();
    }

    public class Iterator <T>
    {
        int index = 0;
        public T next()
        {
            return list.get(index++);
        }
        public boolean hasNext()
        {
            return list.size() > index;
        }
    }
}
于 2010-06-14T20:21:30.073 に答える
0

私は(個人的に)「doXList/eachXList」とlist.for_each(Action)関数が嫌いです。
定義上、これらのメソッドは副作用を実行するため、副作用にはフラグを立てる必要があります。

の行に沿った一般的な言語機能foreach(item in collection)は明白でよく知られており、私の意見では十分です。

これは個人的な決定であり、Eric Lippert がこのブログ投稿で語っています。投稿は C# 固有のものですが、C# と C# コンパイラの用語で表現されていても、議論は一般的な言語に適用されます。

お役に立てれば

于 2010-06-08T13:57:06.397 に答える
0

ロジック付きのオブジェクトをコンテナクラスに渡してメソッドを呼び出させるのが良いと思います。

たとえば、これSchedulerがロジックを含むPersonクラス、コレクションを含むクラス、およびSchedulePref私がむしろ持っているコレクションである場合:

 Person {
    - preferences: Preference[]

     + scheduleWith( scheduler: Scheduler ) {
            preferences.each ( pref: Preference ) {
                  scheduler.schedule( pref )
            }      
       }
  }

そしてクライアントで

 Client {
      main() {
          scheduler = SchoolScheduler.new
          person    = Person.withId( 123 )
          person.scheduleWith( scheduler )
      }
 }

そして、Schedulerそれぞれ異なるアルゴリズムを持つコンクリートのサブクラスを用意します。

ブロックを受け取るようなものですが、ホルダーの内部 ( Person) とロジックの内部 ( the ) を公開する代わりにScheduler、「ロジック クラス ( the Scheduler) 」にカプセル化された関数も渡します。

これについて考えます。病気になったらピルを飲むと、内部的にはそれが体内で作用していると考えるかもしれません (内部的には、いくつかのピルは肝臓ではなく肺に行かなければならないことを知っているかもしれません)。

別の言い方をすれば、あなたの臓器をすべて私に渡して、体の外で何かをしてください. それは良いことではありません。

于 2010-06-14T21:01:30.070 に答える
0

ゲッターの使用は厄介だと思います-それは最小知識の原則に違反しています。したがって、この点ではファンクターの方が優れていますが、さらに柔軟になる可能性があると思います。関数を取得してリストを反復し、その上で関数を実行するのではなく、戦略オブジェクトを取得し、それにリストを渡して変換することができます。

class A{

    List<B> bs;
    List<C> cs;

    // better than getter but could be better
    void transformBs(Functor f){
        for(B b : bs){
            f.transform(b);
        }
    }

    // more flexible
    void transformCs(Strategy s){
        s.transform(cs);
    }
}
interface Functor{ <T> void transform(T t);}
interface Strategy{ <T> void transform(List<T> list); }
于 2010-06-13T12:21:08.180 に答える