このページの下のコメントを見ました。「デコレータの関係が実行時に変更される」理由と「継承関係がコンパイル時に修正される」理由がわかりません。
デコレーターとデコレーターが装飾するオブジェクトとの関係は実行時に変更される可能性があるため、デコレーターは継承よりも柔軟であることが証明されますが、基本クラスとその拡張機能との間の関係はコンパイル時に修正されます。
このページの下のコメントを見ました。「デコレータの関係が実行時に変更される」理由と「継承関係がコンパイル時に修正される」理由がわかりません。
デコレーターとデコレーターが装飾するオブジェクトとの関係は実行時に変更される可能性があるため、デコレーターは継承よりも柔軟であることが証明されますが、基本クラスとその拡張機能との間の関係はコンパイル時に修正されます。
A、B、Cの3つのクラスがある場合、どのように継承しても、A:BとB:Cのように静的な関係になります。
一方、3つすべてがデコレータである場合は、同じプロセスで動的にA(B(C))やC(A(B))など、任意の順序でデコレータをデコレートできます。
オブジェクトはいつでも飾ることができます。あなたが持っているFileInputStream
としましょう、あなたは実行時にそれを飾ることができBufferedInputStream
ます。FileInputStream
これがクラス継承によって設計された場合、他のタイプにキャスト/変換することはできません。
デコレータを使用すると、オブジェクトを入力として受け取り、ある種のラッパーを返すメソッドを記述しているだけです。デコレータは任意にスマートにすることができ、さまざまな入力などに特化した実装を行うことができます。
継承では、コンパイル時にサブクラスとそのすべての詳細を明示的に宣言する必要があり、その後、実装が修正されます。
これらの例が明確にしていないと思うのは、デコレーターが装飾されたクラスへの参照を持っている、つまりインターフェースを使用していることです。誰かが「リスト」の最後の要素にアクセスしたときに「The End」を出力したいと想像してください。 List を実装し、'MyArrayList、MyLinkedList、MyCopyOnWriteArrayList などを持つすべてのクラスをサブクラス化し、get() メソッドをオーバーライドします (退屈だと思います)。または、デコレータを使用して実装 (つまり、実際のリスト) を渡すこともできます。実行時に、これはそのインターフェースによって参照されるため、新しい get メソッドの実装は 1 つしかありません。この不自然な例 (以下) を考えてみましょう。要点は、List の任意の実装を ListDecorator に渡すことができ、それが機能することです。これを継承で行うことを想像してみてください。
package decorator;
import java.util.ArrayList;
import java.util.List;
public class ListDecorator {
List realList;
public static void main(String[] args) {
// Here we are decorating an ArrayList but it could be anything
// that implements the List interface.
ListDecorator ld = new ListDecorator( new ArrayList() );
for(int i=0; i<10; i++)
ld.add( i );
for(int j=0; j<10; j++)
System.out.println("[j]="+ld.get(j) );
}
ListDecorator(List realList){
this.realList = realList;
}
public void add(Object o){
realList.add( o );
}
public Object get(int i){
if(i == realList.size() -1)
System.out.println("The end");
return realList.get(i);
}
}