基本クラスでオブジェクトのインスタンス化を「フック」しても大丈夫ですか?
-
02-07-2019 - |
質問
さまざまな理由のために独自のツリー実装を作成し、思いついた2つのクラス、ロジックでぎっしり詰まった汎用ツリーノードである「ベース」クラスと、より専門化されたクラスを拡張する別のクラス。
私の基本クラスでは、特定のメソッドには新しいツリーノードのインスタンス化が含まれます(例:子の追加)。これらのインスタンス化は、ロジックをインスタンス化から分離するのを難しくするロジック(たとえば、ネストされたループ内)内にあります。
したがって、特定のクラスでこれらのインスタンスをオーバーライドしないと、誤ったタイプのノードが作成されます。ただし、これらのメソッドには重複しない共有ロジックも含まれているため、これらのメソッドをオーバーライドすることは したくありません!
問題は次のように要約できます:
public class Foo {
public String value() { return "foo"; }
public Foo doStuff() {
// Logic logic logic..
return new Foo();
}
}
class Bar extends Foo {
public String value() { return "bar"; }
}
new Bar().doStuff().value(); // returns 'foo', we want 'bar'
最初に頭に浮かんだのは、クラスを拡張することでオーバーライドできる「作成フック」です。
public Foo createFooHook(/* required parameters */) {
return new Foo();
}
今。それは素晴らしい最初の考えでしたが、ひどいコードが悪臭を放っています。非常に何かがあります... 間違っている。
それは裸で料理をするようなものです。危険で不要なと感じます。
では、この状況にどのように対処しますか
解決
つまり、デザインパターンのコピーを取得して開いた後、自分が欲しいものを発見したのは初めてだと確信しています。
ファクトリーメソッドと呼ばれ、ほとんどが完全に適合しています。私のスーパークラス(上記の例では Foo
)は抽象ではないため、まだ少しいです。これは、サブクラスがフックの実装を強制されないことを意味します。
これはリファクタリングで修正できますが、次のような結果になります。
abstract class AbstractFoo {
public String value() { return "Foo"; }
public AbstractFoo doStuff() {
// Logic logic logic
return hook();
}
protected abstract AbstractFoo hook();
}
class Foo extends AbstractFoo {
protected AbstractFoo hook() { return new Foo(); }
}
class Bar extends AbstractFoo {
public String value() { return "Bar"; }
protected AbstractFoo hook() { return new Bar(); }
}
new Bar().doStuff().value(); // Returns 'Bar'!
他のヒント
Factoryパターンに加えて、Compositeパターンも確認します。ツリーベースの状況でFactoryを使用するのに適しています。
より良いアプローチがあるとは思わない。これらのフックをコンストラクターから呼び出さないように注意してください。