7

インターフェース Subject があるとします。

interface Subject { void request(); }

RealSubject クラスがあります。RealSubject を強化したい場合、RealSubject をラップするプロキシ パターンを使用できます。

class Proxy implements Subject { 
   private RealSubject ref;
   void request(){ ... }
}

または、RealSubject を拡張してメソッドをオーバーライドすることもできます

class EnhancedSubject extends RealSubject {
   @Override
   void request() { ... }
}

どちらのアプローチが優れていますか? 私はリスコフの原理を知っています。EnhancedSubject が Liskov 原則を満たしているとしましょう。あなたはまだ継承を考えていますか?

サブジェクト インターフェイスがない場合 (つまり、RealSubject がインターフェイスを実装していない場合)、プロキシ パターンに実装するインターフェイスがないため、「継承とオーバーライド」が唯一のオプションのようです。サブジェクト インターフェイスがない場合でもプロキシ パターンを適用できますか?

4

2 に答える 2

6

最初の質問である「どちらのアプローチが優れているか」についてお答えください。

個人的には、Interface and Proxy (または Decorator) パターンを使用して、このようなものを実装することを好みます。(参照: 項目 16:有効な Java (第 2 版)の継承よりも構成を優先する)

スーパークラス ( RealSubject) が管理下にない場合 (つまり、同じパッケージ内にあり、Extension 用に特別に設計および文書化されている場合)、その実装をバージョンごとに変更すると、サブクラス ( EnhancedSubject) の実装が壊れる可能性があります。基本的に私が言いたいのは、具体的な実装に直接依存するとコードが脆弱になるということです。

2 番目の質問「がリスコフの原理を満たしている場合EnhancedSubject、それでも継承を考慮しますか?

RealSubjectEnhancedSubjectが制御下にあり、同じライフサイクルでリリースされている場合は、継承を使用しても安全ですが、具体的な実装に直接依存するとコードが脆弱になります。

インターフェースの実装を使用するようになることを願っているもう 1 つのポイントは、単体テストです。

たとえば、単体テストを適用するケースを使用すると、オブジェクト階層全体を完全にテストするよりも、クラスを具体的にテストできるようRealSubjectに、のProxy実装にモック依存関係を挿入する方がはるかに簡単です。 、および、期待どおりに動作することを確認するだけです。SubjectProxyRealSubjectEnhancedSubjectEnhancedSubject

しかし、それがすべて非常に単純な API であり、将来的にほとんど変更されない場合、具体的な実装は単純に単純であると言えると思います。And Keep It Simple Stupid (KISS) は最良のポリシーの 1 つです。

サブジェクト インターフェイスがなくてもプロキシ パターンを適用できますか?RealSubject別のクラスにインジェクトしてRealSubject内部的に使用することもできますが、使用する APIRealSubjectが具象クラスに直接依存している場合は、継承を使用するしかありません。

于 2010-10-19T05:32:37.523 に答える
1

プロキシ/デコレータの利点は、派生クラスで再利用できることです。これにより、クラスの実装からプロキシを分離できます。(私が無効なJavaを書いたら、あなたは私を許す必要があります..それはしばらくの間です)

この場合、おそらく次のように記述します。

class LoggingSubjectProxy implements Subject
{
   private Subject ref;
   void request() 
   { 
      log("Called request");
      ref.request();
   }
}

今、あなたはすることができます

LoggingSubjectProxy l;
if(dosimple)
{
    l.ref = SimpleSubject();
}
else
{
    l.ref = ComplexSubject();
}
l.request()

必要な拡張機能に対してこれがやり過ぎである場合は、単純な継承とオーバーライドを使用する必要があります。

于 2010-10-19T04:49:54.450 に答える