web-dev-qa-db-ja.com

既存のオブジェクトに機能を追加するにはどうすればよいですか?

明確に定義された機能をある程度備えたインターフェースがあります。まあ言ってみれば:

_interface BakeryInterface {
  public function createCookies();
  public function createIceCream();
}
_

これはインターフェースのほとんどの実装でうまく機能しますが、いくつかの例では、新しい機能を追加する必要があります(おそらく、新しいメソッドcreateBrownies()に組み込まれるなど)。これを行う明白な/素朴なアプローチは、インターフェースを拡張することです:

_interface BrownieBakeryInterface extends BakeryInterface {
  public function createBrownies();
}
_

ただし、既存のAPIを変更せずに新しい機能を追加できない(新しいインターフェイスを使用するようにクラスを変更するなど)という点で、かなり大きな欠点があります。

adapter を使用して、インスタンス化後に機能を追加することを考えていました。

_class BrownieAdapter {
  private brownieBakery;

  public function construct(BakeryInterface bakery) {
    this->brownieBakery = bakery;
  }

  public function createBrownies() {
    /* ... */
  }
}
_

これは私に次のようなものをもたらします:

_bakery = new Bakery();
bakery = new BrownieBakery(bakery);
bakery->createBrownies();
_

これは問題の良い解決策のように見えますが、私はそれを行うことによって古い神々を目覚めさせているのだろうかと思っています。アダプターは使えますか?従うべきより良いパターンはありますか?それとも私は本当に弾丸を噛んで元のインターフェースを拡張するだけなのでしょうか?

25
user8

ハンドルボディパターン は、要件、言語、および抽象化の必要なレベルに応じて、説明に適合します。

純粋主義的なアプローチは Decorator pattern です。これはまさにあなたが探していることを行い、動的にオブジェクトに責任を追加します。あなたが実際にパン屋を造っているなら、それは間違いなくやり過ぎです、そしてあなたはただアダプターで行くべきです。

14
yannis

水平再利用の概念を調査します。ここでは、 Traits のようなものを見つけることができますが、まだ実験的ですしかし、すでにプロダクションプルーフ アスペクト指向プログラミング そして時々嫌われる Mixins =。

クラスにメソッドを直接追加する方法も、プログラミング言語に依存します。 Rubyは monkey-patching を許可しますが、Javascriptの prototype-based 継承、クラスが実際には存在しない場合、オブジェクトを作成し、それをコピーして追加し続けるだけです。例:

var MyClass = {
    do : function(){...}
};

var MyNewClass = new MyClass;
MyClass.undo = function(){...};


var my_new_object = new MyNewClass;
my_new_object.do();
my_new_object.undo();

最後に、水平方向の再利用、またはランタイムの「変更」とクラス/オブジェクトの動作の「追加」を reflection でエミュレートすることもできます。

5
dukeofgaming

bakeryインスタンスがその動作を動的に変更する必要がある(ユーザーのアクションなどに応じて)必要がある場合は、Decorator patternを使用する必要があります。

bakeryがその動作を動的に変更しないが、Bakery class(外部APIなど)を変更できない場合は、Adapter patternを使用する必要があります。

bakeryがその動作を動的に変更せず、Bakery classを変更できる場合は、既存のインターフェースを拡張するか(最初に提案したとおり)、または新しいインターフェースBrownieInterfaceBakeryに2つのインターフェースBakeryInterfaceBrownieInterfaceを実装させます。
それ以外の場合は、正当な理由なしに、(Decoratorパターンを使用して)コードに不必要な複雑さを追加します!

4
Dime

式の問題が発生しました。 Stuart Sierraによるこの記事 は、clojuresソリューションについて説明しますが、Javaに例を示し、クラシックOOで人気のあるソリューションをリストします。

Chris Houserによるこのプレゼンテーションもあります ほぼ同じ理由について説明しています。

2
Pavel Penev