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

3 に答える 3

4

私は常に、継承 (最初のオプション) よりも合成 (2 番目のオプション) による再利用を好みました。

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

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

これにより、各アプリケーションは、その特定のアプリケーションに関連するフレームワークの部分を再利用できるようになり、すべてを強制的に使用する必要がなくなり、個々のアプリケーションの自由度が高まります。継承による再利用は、現在考えている構造に正確に適合しないアプリケーションが将来ある場合、非常に制限されることがあります。

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

于 2009-07-04T16:39:07.457 に答える
0

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

したがって、クライアントは(Javaで)次のようなインターフェースを実装するだけです

public interface ClientCode {

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

フレームワークコードはこれの実装で構成され、runClientStuff()必要に応じて呼び出します。

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

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

于 2009-07-04T16:06:45.197 に答える
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();
}
于 2009-07-04T16:29:10.097 に答える