2009-07-04 19 views
2

私は共通の構造を共有し、同じことをいくつか同じ方法(ログ、データベース接続、環境設定など)で行う必要がある、再利用可能なコンポーネントを構造化する際のアドバイスを探しています。コードは強く静的に型付けされた言語(JavaやC#など)で書かれています。私はこの問題を両方とも解決しなければなりませんでした。現時点で私はこれを持っています:再利用可能なコードのアーキテクチャ

abstract class EmptyApp //this is the reusable bit 
{ 
    //various useful fields: loggers, db connections 

    abstract function body() 
    function run() 
    { 
     //do setup 
     this.body() 
     //do cleanup 
    } 
} 

class theApp extends EmptyApp //this is a given app 
{ 
    function body() 
    { 
     //do stuff using some fields from EmptyApp 
    } 

    function main() 
    { 
     theApp app = new theApp() 
     app.run() 
    } 
} 

良い方法はありますか?多分次のように?私は、トレードオフを計量トラブルを抱えて...

abstract class EmptyApp 
{ 
    //various fields 
} 

class ReusableBits 
{ 
    static function doSetup(EmptyApp theApp) 

    static function doCleanup(EmptyApp theApp) 
} 

class theApp extends EmptyApp 
{ 
    function main() 
    { 
     ReusableBits.doSetup(this); 
     //do stuff using some fields from EmptyApp 
     ReusableBits.doCleanup(this); 
    } 
} 

1つの明らかなトレードオフは、オプション2で、「フレームワーク」はtry-catchブロックでアプリをラップすることができないということです...

答えて

4

私はいつも継承(最初のオプション)ではなく、コンポジション(2番目のオプション)を使用して再利用しています。

継承は、コードの再利用ではなくクラス間の関係がある場合にのみ使用してください。

あなたの例では、それぞれのアプリケーションが必要に応じて使用する1つのことをそれぞれ行う複数のReusableBitsクラスがあります。

これにより、各アプリケーションは、すべてのアプリケーションを強制することなく、特定のアプリケーションに関連するフレームワークの部分を再利用することができます。将来的にいくつかのアプリケーションがありますが、現在の構造に正確に収まらないアプリケーションがあると、継承による再利用は非常に制限的になることがあります。

フレームワークを別々のユーティリティに分割すると、単体テストとテスト駆動型開発がずっと簡単になります。

0

フレームワークをカスタマイズ可能なコードに呼び出さないのはなぜですか?クライアントがオブジェクトを作成し、それをフレームワークに挿入します。フレームワークが初期化され、setup()などを呼び出し、クライアントのコードを呼び出します。完了すると(または例外がスローされた後でも)、フレームワークはcleanup()を呼び出して終了します。

だからあなたのクライアントは、単純な(Javaで)としてのインターフェースを実装し

public interface ClientCode { 

    void runClientStuff(); // for the sake of argument 
} 

とフレームワークコードこのの実装で構成され、必要な時はいつでもrunClientStuff()を呼び出しています。

は、アプリケーションフレームワークからを派生させるのではなく、特定の契約に準拠したクラスを提供するだけです。アプリケーションから派生したものではないため、依存関係が静的ではないため、実行時にアプリケーション設定を構成することができます(たとえば、クライアントがアプリケーションに提供するクラス)。

上記のインターフェイスは、複数のメソッドを持つように拡張することができ、アプリケーションはライフサイクルのさまざまな段階(たとえば、クライアント固有のセットアップ/クリーンアップを提供する)で必要なメソッドを呼び出すことができます。

0

継承は、継承しているすべてのオブジェクトがコードをその類似性に再利用する場合にのみ選択することを忘れないでください。発信者が同じ分裂でそれらとやりとりできるようにしたい場合は、 私があなたに言及したことがあなたに当てはまるならば、私の経験に基づいて、あなたの基底/抽象クラスに共通ロジックを持つ方が良いでしょう。

これは、C#でサンプルアプリケーションを書き直す方法です。

abstract class BaseClass 
{ 
    string field1 = "Hello World"; 
    string field2 = "Goodbye World"; 

    public void Start() 
    { 
     Console.WriteLine("Starting."); 
     Setup(); 
     CustomWork(); 
     Cleanup(); 
    } 

    public virtual void Setup() 
    {Console.WriteLine("Doing Base Setup.");} 

    public virtual void Cleanup() 
    {Console.WriteLine("Doing Base Cleanup.");} 

    public abstract void CustomWork(); 
} 

class MyClass : BaseClass 
{ 
    public override void CustomWork() 
    {Console.WriteLine("Doing Custome work.");} 

    public override void Cleanup() 
    { 
     Console.WriteLine("Doing Custom Cleanup"); 
     //You can skip the next line if you want to replace the 
     //cleanup code rather than extending it 
     base.Cleanup(); 
    } 

} 

void Main() 
{ 
    MyClass worker = new MyClass(); 
    worker.Start(); 
} 
関連する問題