私はすでにこのコアクラス構造を持っていますそれは変更できません:
class A {
//some basic fields and methods
}
class B {
//some another basic fields and methods
}
これはコアクラスであり、既存のシステムにいくつかの機能を追加しています。このクラスにいくつかの一般的な機能を追加する必要があります。 A
とB
の実装はほとんど同じです。私の現在の解決策は、次のようなものを構築することです:
class A {
//some basic fields and methods
}
class B {
//some another basic fields and methods
}
class Foo extends A {
//my new features
}
class Bar extends B {
//my new features (identical with Foo)
}
問題は、AまたはBクラスを変更できず、それらを変更できないだけではないことです。need base A
とB
クラスの両方- および存在するFoo
およびBar
クラス。したがって、リフレクションを使用してAおよびBクラスを変更することは、解決策ではありません。
私はこの機能をいくつかのapiオブジェクトとして追加しようとしました:
class FeatureApi {
my new features
}
class Foo extends A {
FeatureApi api;
}
class Bar extends B {
FeatureApi api;
}
しかし、別の問題が発生します。新しいメソッドは私のクラスのフィールド/メソッドにアクセスする必要があります。しかし、私はそれらをapi-objectに持っていません。
要約すると:
A
とB
を拡張するカスタムクラスを作成したいPD 2主な目的は、2つの変更可能な基本クラスから継承した、2つのカスタムクラスにまったく同じ動作を実装することです。今見ているように、基本クラスの継承は意味をなさないので、それを削除して私の質問を明確にしました。
あなたはFeatureApiの例でそれを行うことができます。 AまたはBの保護フィールドをラップされたFeatureApiに公開するには、いくつかの変更が必要です。
(私はc#で行くつもりです)
class FeatureApi
{
FeatureApi(IExposeStuff parent) {..}
public string myNewFeature()
{
var info = parent.GetProtectedInfo();
//do stuff
}
}
interface IExposeStuff
{
string GetProtectedInfo();
}
class NewA : A, IExposeStuff
{
FeatureApi api;
public NewA()
{
this.api = new FeatureApi(this)
}
public string GetProtectedInfo()
{
return this.protectedInfo;
}
}
残念ながら、あなたは少し緊張しています。他の誰かが、変更できない継承階層にあなたをロックしました。 A
およびB
の動作方法によっては、動作を実装するために各クラスを個別に拡張する必要がある場合があります。ここでは、直面する制約に応じたいくつかのシナリオを示します。
A
およびB
のメソッドをオーバーライドする必要があります。このシナリオでは、A
およびB
が独自のメソッドを呼び出し、実装している機能はこれらの呼び出しをインターセプトする必要があります。例えば:
class A {
private void fizz() {
buzz();
}
void buzz(); // <- you must override this to implement your functionality
}
このシナリオでは、A
のrawインスタンスで動作を取得するonly方法は、A
を拡張してbuzz
をオーバーライドすることです。同様に、B
のインスタンスで動作を取得する唯一の方法は、B
を拡張してbuzz
をオーバーライドすることです。それらを個別に拡張する必要がありますが、buzz
の2つのオーバーライドを静的ユーティリティメソッドまたはA
の個別のインスタンスメソッドに呼び出すことにより、コードを再利用できる場合があります。
この状況は厄介で、コードの複製が行き詰まっており、同じ方法でより多くの機能を実装する必要がある場合は、4つのクラスを拡張する必要があります。もう一度行う必要がある場合は、拡張するクラスが8つあります。ご覧のとおり、このアプローチはまったく拡張性がありません。
A
およびB
のメソッドをオーバーライドする必要はありません。このシナリオでは、A
およびB
のメソッドは、新しい機能に「コールバック」する必要はありません。このシナリオmightでは、A
とB
の許容度に応じて、デコレータパターンを介して委任を使用できます。このアプローチには、A
をA
の「実際の」インスタンスを取得し、それにすべてのメソッド呼び出しを委譲するサブクラスを使用してA
を拡張し、B
を拡張してB
を装飾します。
このアプローチが最初のアプローチより優れている1つのsmallの利点は、A
の「実際の」インスタンスを使用するユーティリティメソッドの観点から、追加機能を実装できることです。 B
はA
であるため、A
デコレータとB
デコレータの両方からこのユーティリティメソッドを呼び出すことができます。
A
が特定のデータを取るコンストラクターしか持っていない場合、サブクラスはスーパークラスのコンストラクターを呼び出す必要があるため、このアプローチは実行できない場合があります。スーパークラスに渡されたデータをファッジすることもできますが、そうするとハッキングされて壊れやすくなります(もしA
がファッジされたデータが失敗したという検証を追加したらどうなるでしょうか?)。
A
およびB
のインターフェースを導入できる場合は、オプションがかなり開きます。この場合、具象スーパークラスのコンストラクターの呼び出しを心配することなく、デコレーターパターンをきれいに実装できます。それでも2つのデコレータを実装する必要がありますが、追加したすべての機能は、装飾されたオブジェクトを取得する静的ユーティリティメソッドで実装できるため、ボイラープレートを複製するだけで済みます。
このアプローチでは、デコレータインターフェースを公開する必要がないことに注意してください。コードはA
とB
にのみ依存します。したがって、A
とB
の両方に機能を追加する必要がある場合は、2回実装するだけで済みます。 3回目に機能を追加する必要がある場合でも、2回実装するだけで済みます。したがって、このアプローチは最初のアプローチよりもはるかに優れています。
カプセル化を使用しないのはなぜですか? AとBをそれぞれFooとBarのメンバーにします。マーシャリング、検証などを行うために、現在のAおよびBオブジェクトを返すものに新しい抽象化レイヤーを導入します。
継承やインターフェースは使用しないでください。どちらも状況に不適切です。代わりに封じ込めを使用する必要があります。
新しいクラスMyAにクラスAのプライベートインスタンスを作成します。新しいものを実装します。 Aの閉じた機能が必要なときはいつでも、Aを呼び出します。Aの閉じたメソッドと同じ名前でデリゲートするだけの独自の新しいメソッドを作成できます。 Bも同じようにします。