0

私自身、ここで何を求めているのかよくわかりませんので、少々お待ちください。

基本的に、ソケットなどの外部ソースから受信したコマンドを処理できなければならないアプリケーションがあります。

すべてのコマンドは、このコマンドに固有の 2 つのデータ構造を使用します。1 つの構造は、このコマンドの処理に関連する一連の引数を保持し、もう 1 つは結果データを受け取ります。

当然のことながら、データ転送ハンドラー クラスは、どのコマンドがどの構造体を使用するかについて何も知らないため、コマンドを受信した後に最初に呼び出されるものは次のようになります。

CSocketHandler::ReceiveCommand(int CommandCode, const TBuffer& Args, TBuffer& Result);

最後のものは次のようになります。

CClassBar::ProcessCommandFoo(const TFooArgs& Args, TFooResult& Result);

ここで欠けているのは、TBuffer を TFooArgs に変換し、正しいメソッドを呼び出し、TFooResult を TBuffer に戻す部分だけです (変換は簡単です)。

さまざまなハンドラー クラスとコマンドの量は非常に多くなることが予想されるため、ここで見ているのは、さまざまなデータ型に対して同じことを行い、さまざまな関数を何度も呼び出す 3 マイルの長さのメソッドです。

だから私の質問 - この退屈でエラーが発生しやすいタスクを自動化することは可能ですか? できれば、新しいメッセージ処理メソッドを定義するだけで十分ですが、私は喜んで妥協します。

4

1 に答える 1

2

ジェネリックコードは良いです。

  1. TBufferfrom toXArgsと from to のXResult2つの convert メソッドを作成します。TBuffer
  2. 自動コマンド ラッパーを作成する
  3. mapこれらのラッパーに自動的にディスパッチする を実装します

関数へのポインタまたは継承のいずれかを使用して実行できます。継承の方が簡単だと思います...

class BaseCommand {
public:
    virtual ~BaseCommand() {}

    virtual TBuffer invoke(TBuffer const& tb) = 0;
};

template <typename Args, typename Result>
class CommandT: public BaseCommand {
public:
    virtual TBuffer invoke(TBuffer const& tb) {
        Args const a = from_buffer(tb, &a); // free function
        Result const r = this->invoke(a);
        return to_buffer(r);            // free function
    }

private:
    virtual Result invoke(Args const&) = 0;
};

注: ごまかしとして、自動引数推定を取得するために に渡し&aますfrom_buffer。ポインターは使用されていないことが予想されます。

ですから、引数と結果があるとしましょう (どちらintも簡単です):

int from_buffer(TBuffer const& tb, int const*) {
    return tb.asInt();
}

TBuffer to_buffer(int i) {
    return TBuffer(i);
}

そして、以下を処理するコマンドを実装できますint

class IntCommand: public CommandT<int, int> {
    virtual int invoke(int const& i) override { return i; }
};

よし、発送に移ろう。アイデアは、各コマンドをその ID に登録することです。

template <typename T>
std::unique_ptr<BaseCommand> make_command() { return std::unique_ptr<T>(new T()); }

static std::map<int, std::unique_ptr<BaseCommand>> Commands;

int main() {
    Commands.insert(std::make_pair(1, make_command<IntCommand>()));
    // lots of them...

    // starts processing
}

そして、次のSocketHandlerものがあります。

void SocketHandler::ReceiveCommand(int code, TBuffer const& a, TBuffer& r) {
    typedef std::map<int, std::unique_ptr<BaseCommand>>::const_iterator const_it;

    const_it it = Commands.find(code);
    if (it == Commands.end()) {
        std::cerr << "Unknown command: " << code << "\n";
        throw std::runtime_error("Unknown command");
    }

    r = it->second->invoke(a);
}
于 2012-06-07T15:49:39.193 に答える