JAVA PECS法則

7134 ワード

PECSとは?PECSとは「Producer Extends,Consumer Super」のこと.言い換えれば、パラメトリックタイプが生産者を表す場合、;消費者を表す場合は.
以下は簡単なStackのAPIインタフェースです.

  
  
  
  
  1. public class Stack<E>{
  2. public Stack();
  3. public void push(E e):
  4. public E pop();
  5. public boolean isEmpty();
  6. }

一連の要素を順番にStackに入れる方法を追加したいと仮定すると、次のような実現方法が考えられます.

  
  
  
  
  1. public void pushAll(Iterable<E> src){
  2. for(E e : src)
  3. push(e)
  4. }

Stackがあると仮定し,Integer,LongなどのNumberのサブタイプの集合を柔軟に処理したい.

  
  
  
  
  1. Stack<Number> numberStack = new Stack<Number>();
  2. Iterable<Integer> integers = ....;
  3. numberStack.pushAll(integers);

この場合、コードコンパイルはパスできません.タイプNumberとIntegerでは、後者はNumberのサブクラスですが、任意のNumberセット(List)に対してIntegerセット(List)のスーパークラスではありません.汎用型は可変ではないためです.
幸いjavaは有限ワイルドカードというパラメータ化タイプを提供しており、pushAllパラメータは「EのサブタイプのIterableインタフェース」に置き換えられています.

  
  
  
  
  1. public void pushAll(Iterable<? extends E> src){
  2. for (E e: src)
  3. push(e);
  4. }

これで正しくコンパイルできますが、ここのとは、いわゆるproducer-extendsである.ここのIterableは生産者ですが、.だってIterableは、任意のEのサブクラスを収容することができる.操作を実行すると、反復可能なオブジェクトの各要素はEとして操作できます.
これに対応して、Stackコレクションから各要素をポップアップし、指定したコレクションに追加するメソッドpopAll()メソッドがあると仮定します.

  
  
  
  
  1. public void popAll(Collection<E> dst){
  2. if(!isEmpty())
  3. dst.add(pop());
  4. }

StackオブジェクトとCollectionオブジェクトがあるとします.

  
  
  
  
  1. Stack<Number> numberStack = new Stack<Number>();
  2. Collection<Object> objects = ...;
  3. numberStack.popAll(objects);

同じように上のコードも通らないので、解決策はCollection.ここのobjectsは消費者です.objectsセットに要素を追加するからです.Collectionの後、objectsがどんなタイプの集合であろうと、少し満足しているのは彼がEのスーパークラスであるため、このパラメータ化タイプが具体的にどんなタイプであろうと、Eをobjects集合に組み込むことができる.
まとめ:
1、collectionを巡り、各要素を操作したい場合、この集合時に生産者(生産要素)はCollection
2、collectionに要素を追加したい場合は、集合時に消費者(消費要素)はCollection