0

ClientInterfaceクラスがあります。このクラスは、Strategyパターンを使用して、インターフェイスAbaseとBbaseにそれぞれ準拠する2つの複雑なアルゴリズムを編成します。ClientInterfaceは、アルゴリズムが動作するデータを(合成を介して)集約します。データは、データインターフェイスに準拠する必要があります。

私がやろうとしたのは、実行時にさまざまな戦略とデータの実装を選択できる単一のClientInterfaceクラスを用意することです。アルゴリズムとデータの実装は、入力ファイルから文字列を読み取り、ClientInterfaceコンストラクターでアルゴリズムとデータの実装を選択するファクトリメソッドを使用して選択されます。データとアルゴリズムの実行時の選択は、以下のコードモデルでは提供されていません。

データの実装は、マップ、リスト、unordered_mapなどに基づいて、2つの複雑なアルゴリズム(AbaseおよびBbaseで実装された戦略)の効率が、データに使用される異なるコンテナーでどのように変化するかをテストできます。

さらに、データはさまざまな要素(ElementBase実装)を集約します。さまざまな要素の実装もClientInterfaceの効率に大きな影響を与えますが、要素は実際にはさまざまなライブラリからの実装とは互いに素なタイプです。既存のアプリケーションをプロファイリングすると、Element操作がボトルネックの1つであることが示されるため、これは事実としてわかっています。

コンテナでポリモーフィズムを使用する場合、そこには「boost / ptr_container」がありますが、データには数百万ではないにしても数十万の要素が格納されます。この場合、要素にポリモーフィズムを使用すると、ClientInterfaceにかなりのオーバーヘッドが発生しますが、データをElementタイプのクラステンプレートにすることを選択すると、ClientInterfaceクラスを静的に定義することになります。つまり、各要素ごとにクライアントアプリケーションを生成します。少なくとも入力してください。

実行時に取得された同じ数の要素とClientInterface構成に対して、要素タイプのポリモーフィズムの使用によって引き起こされるオーバーヘッドが、データとアルゴリズムの実装のすべての構成に同じ影響を与えると想定できますか?この場合、自動テストを実行し、データ実装と要素実装の構成を決定し、生産的なコードで使用される静的に構成されたEfficientClientInterfaceを定義できますか?

目標:テストハーネスを準備しました。実行時にアルゴリズムと要素を変更すると、ループ内で単一のアプリケーションを使用できるため、テストケースファミリーのテストを自動化しようとしています。これは実行時に構成され、その出力は効率のために測定されます。実際の実装では、少なくとも6つのアルゴリズムインターフェイス、3〜4のデータ実装を扱っており、少なくとも3つの要素の実装を見積もっています。

だから、私の質問は次のとおりです。

1)戻り型に対してオーバーロードが機能していない場合、Elementはどのようにさまざまな操作をサポートできますか?操作をテンプレートにする場合は、コンパイル時に定義する必要があります。これは、自動テスト手順を台無しにします。

2)目標を達成するために、このコードをより適切に設計するにはどうすればよいですか?

3)この問題に対するより良い全体的なアプローチはありますか?

コードモデルは次のとおりです。

#include <iostream>
#include <memory>

class ElementOpResultFirst
{};

class ElementOpResultSecond
{};

class ElementBase
{
    public: 

        // Overloading does not allow different representation of the solution for the element operation.
        virtual ElementOpResultFirst elementOperation() = 0; 
        //virtual ElementOpResultSecond elementOperation() = 0; 

}; 

class InterestingElement
: 
    public ElementBase
{
    public: 
        ElementOpResultFirst elementOperation() 
        {
            // Implementation dependant operation code. 

            return ElementOpResultFirst(); 
        } 
        //ElementOpResultSecond elementOperation() 
        //{
            //// Implementation dependant operation code.

            //return ElementOpResultSecond(); 
        //} 
};

class EfficientElement
: 
    public ElementBase
{
    public: 
        ElementOpResultFirst elementOperation() 
        {
            // Implementation dependant operation code.

            return ElementOpResultFirst(); 
        } 
        //ElementOpResultSecond elementOperation() 
        //{
            //// Implementation dependant operation code.

            //return ElementOpResultSecond(); 
        //} 
};

class Data
{
    public: 
        virtual void insertElement(const ElementBase&) = 0;  
        virtual const ElementBase& getElement(int key) = 0;
};

class DataConcreteMap
:
    public Data
{
    // Map implementation

    public: 
        void insertElement(const ElementBase&)
        {
            // Insert element into the Map implementation.
        } 
        const ElementBase& getElement(int key)
        {
            // Get element from the Map implementation.
        } 
};

class DataConcreteVector
:
    public Data
{
    // Vector implementation

    public: 
        void insertElement(const ElementBase&)
        {
            // Insert element into the vector implementation.
        } 
        const ElementBase& getElement(int key)
        {
            // Get element from the Vector implementation
        } 
};

class Abase
{
    public: 
        virtual void aFunction() = 0; 
};

class Aconcrete
:
    public Abase
{
    public: 
        virtual void aFunction() 
        {
            std::cout << "Aconcrete::function() " << std::endl;
        }
};

class Bbase
{
    public: 
        virtual void bFunction(Data& data) = 0; 
};

class Bconcrete
:
    public Bbase
{
    public: 
        virtual void bFunction(Data& data) 
        {
            data.getElement(0); 
            std::cout << "Bconcrete::function() " << std::endl;
        }
};

// Add a static abstract factory for algorithm and data generation. 

class ClientInterface
{
    std::unique_ptr<Data>  data_; 
    std::unique_ptr<Abase> algorithmA_; 
    std::unique_ptr<Bbase>  algorithmB_; 

    public: 

        ClientInterface()
            :
                // A Factory Method is defined for Data, Abase and Bbase that 
                // produces the concrete type based on an entry in a text-file.
                data_ (std::unique_ptr<Data> (new DataConcreteMap())), 
                algorithmA_(std::unique_ptr<Abase> (new Aconcrete())),
                algorithmB_(std::unique_ptr<Bbase> (new Bconcrete()))
        {}

        void aFunction()
        {
            return algorithmA_->aFunction(); 
        }

        void bFunction()
        {
            return algorithmB_->bFunction(*data_); 
        }
};

// Single client code: both for testing and final version.
int main()
{
    ClientInterface cli; 

    cli.aFunction(); 
    cli.bFunction(); 

    return 0; 
};
4

1 に答える 1

1

私がやろうとしたことは、実行時にさまざまな戦略とデータの実装を選択できる単一の ClientInterface クラスを持つことです。アルゴリズムとデータの実装は、入力ファイルから文字列を読み取り、ClientInterface コンストラクターでアルゴリズムとデータの実装を選択する Factory Method を使用して選択されます。データとアルゴリズムの実行時の選択は、以下のコード モデルでは提供されていません。

ここにそのいくつかの基礎があるように聞こえます:テストするファイルのセットを生成し、それを使用して適切な異なる入力セットを生成します。または、ファイルと文字列の読み取りが分離されるように Factory 関数をリファクタリングして、コードから文字列を使用してファクトリ関数 [internals] を呼び出すことができるようにします。

同じ数の要素と実行時に取得される ClientInterface 構成について、要素タイプのポリモーフィズムの使用によって引き起こされるオーバーヘッドが、データとアルゴリズムの実装のすべての構成に同じ影響を与えると仮定できますか? この場合、自動化されたテストを実行し、Data 実装と Element 実装の構成を決定し、静的に構成された EfficientClientInterface を生産コードで使用するように定義できますか?

あなたがその仮定を立てることはできないと思います。実装が異なれば、アルゴリズムへの影響も異なる可能性があります。たとえば、100 バイトの文字列をコピーするのは、4 バイトの整数をコピーするよりもはるかに困難です。したがって、データとは何か、またデータがどのように編成されるかは、作業に何らかの影響を与えます。もちろん、要素に実際に何が含まれているかについて詳しく説明していないため、すべて当て推量です。

1) 戻り値の型に対してオーバーロードが機能しない場合、要素はどのようにさまざまな操作をサポートできますか? 操作をテンプレートにすると、コンパイル時に定義する必要があり、自動テスト手順が台無しになります。

ElementBase 参照またはポインタを返すファクトリ クラスを作成しますか? それがこの質問に対する私の即時の反応ですが、繰り返しになりますが、あなたの質問の詳細は十分に曖昧であるため、確実に言うのは困難です.

実際のアプリケーションでは、これはどのように機能しますか? それがテンプレートによって行われる場合は、テンプレートによってテストコードを実装し、実際のシステムが実行する可能性が高いと思われる現実的なバリエーションを選択して記入することをお勧めします。

2) 目標を達成するために、このコードをより適切に設計するにはどうすればよいですか?

製品コードの再利用を試みますか?

3) この問題に対するより良い全体的なアプローチはありますか?

まだ確かではない。

于 2013-02-09T14:20:59.243 に答える