私は OOP コードを書きながら、エレガント オブジェクトのいくつかのプラクティスを適用します。
そのうちの 1 つは、クラスが final であることです。これは、継承によって拡張することはできず、合成によってのみ拡張できることを意味します。
利点は単純さです。このように、各オブジェクトはまとまりのあるブロックとして見られるということです。クライアントが関心を持っているのは、その露出した動作です。これ以上何もない。代わりに、拡張を通じて、クライアントはそれを破ることができます。
たとえば、オブジェクトはその 2 つのメソッドを相互に関連付けることができます。したがって、そのうちの 1 つを拡張して置き換えることができれば、もう 1 つを壊すことができます。このため、確かに、その実装を確認する必要があります。このようにして、拡張と拡張の間の結合を増やします。
言い換えれば、最終クラスは、公開された動作のみを気にする必要があるという考えを強制します。そして実装ではありません。それにもかかわらず、それは私たちがそれらについてどのように推論するかを変える必要があります. Alias パターンは、この変更の側面を簡素化します。
Alias パターンを使用すると、クラスがオブジェクトをサブクラス化または変更せずに構築できる方法を拡張できます。
いくつかの必須パラメーターを使用してオブジェクトを作成する最終クラスを想定します。オブジェクトを作成する別の方法を追加するにはどうすればよいでしょうか?たとえば、不足しているパラメーターの 1 つ以上にデフォルト値を使用するコンストラクターを追加するにはどうすればよいでしょうか?
1 つの方法は、別のコンストラクターをクラスに追加することです。しかし、これは手に負えなくなる可能性があります。さらに、それは不可能である可能性があります。たとえば、前述の最終クラスは外部ライブラリにある可能性があります。
このアプローチのもう 1 つの欠点は、最終クラスを汚染する可能性があることです。たとえば、JSON を指定してオブジェクトを構築する final クラスを作成できます。しかし、しばらくすると、XML も追加する必要があります。ご想像のとおり、XML を JSON にマップするコードを追加すると、必然的にそのクラスが汚染されます。
ただし、Alias パターンは final クラスに限定されません。たとえば、パラメーターは同じだがセマンティックが異なる 2 つのコンストラクターを使用することはできません。
この問題を解決するには、静的ファクトリ メソッドをクラス コードに追加します。しかし、同じ前述の欠点がこのアプローチに影響を与えます。つまり、これは手に負えなくなります。これは常に可能であるとは限りません。これはクラスを汚染します。
両方の問題に対するより良いアプローチは、目的のコンストラクターの動作を持つ別のクラスを作成することです。このクラスは、独自の構築ロジックをカプセル化します。そして、実際の作成を含め、すべてを他のクラスに委譲します。これが Alias パターンです。
次の場合に Alias パターンを使用します。
最終クラスのコンストラクターを追加または変更する必要があります。
クラスのコンストラクターを変更またはサブクラス化せずに追加または変更する場合。
変更またはサブクラス化せずに、同じパラメーターを持つクラスのコンストラクターが 2 つ以上必要です。
構造は簡単です。 Alias
とAliased.
AnInterface
インターフェイスを宣言します。
Aliased
AnInterface
を実装します。
1 つ以上のコンストラクターを公開します。
Alias
AnInterface
を実装します。Aliased
オブジェクトへの参照を維持します。Aliased
オブジェクトにすべてを委譲します。Alias
は独自の規則に従ってAliased
オブジェクトを構築し、その参照を維持します。次に、すべてをエイリアスに委任します。
エイリアス パターンには、次の結果があります。
Alias パターンを実装するには、次のものが必要です。
インターフェイスを定義します。
クラスで以前に定義されたインターフェイスを実装します。これはエイリアス化されたものになります。
以前に定義したインターフェイスをエイリアス クラスで実装するには、次のものが必要です。
以下の Java っぽいコードは Alias パターンを表しています。このコードでは、エイリアスは必須パラメーターのデフォルト値を挿入します。
interface AnInterface { void aMethod(); Something anotherMethod(); } final class Aliased implements AnInterface { private final A a; private final B b; Aliased(final A a, final B b) { this.a = a; this.b = b; } void aMethod() { // implementation } Something anotherMethod() { // implementation } } final class Alias implements AnInterface { private final Aliased aliased; Alias(final A a) { this( new Aliased( a, new InstanceOfB(...) ) ); } private Alias(final Aliased aliased) { this.aliased = aliased; } void aMethod() { this.aliased.aMethod(); } Something anotherMethod() { return this.aliased.anotherMethod(); } }
ある程度、Alias パターンはオブジェクトの構造を装飾する方法と見なすこともできます。このビジョンは、クラスを、オブジェクトを作成する責任を持つオブジェクトと見なす場合に特に当てはまります。