1

次のことをしているクラスをイメージする

class AClass
{
    AClass() : mode(0) {}
    void a()
    {
        if (mode != 0) throw ("Error mode should be 0");
        // we pass the test, so now do something
        ...
        mode = 1;
    }
    void b()
    {
        if (mode != 1) throw("Error mode should be 1");
        // we pass the test, so now do something
        ...
    }
    int mode;
};

このクラスには多くのメソッド (簡単に 20 より多い) が含まれており、これらのメソッドのそれぞれについて、mode の値をチェックする必要がありますが、これは明らかに多くのコードの重複です。さらに、モード !=0 の場合にエラーをスローするメソッドと、モード != 1 の場合にエラーをスローするメソッドの 2 つのカテゴリを識別することができます。これらのメソッドを 2 つのカテゴリにグループ化することは可能でしょうか (カテゴリ A =モード != 0) の場合にエラーをスローするメソッドと、モード != 1) の場合にエラーをスローするメソッドのカテゴリ B?

編集:現在の回答を見ると、質問を定式化する方法がわかり、問題はおそらく十分に明確ではありません。私が避けたいのは、クラスの各メソッドで関数を呼び出さなければならないことです。メソッドの先頭にコードを書くか、このコードを関数に入れてこの関数を呼び出すかは問題ではありません。問題は、これを一緒に回避できるかどうかです。コンテキストに応じて、クラスのメソッドへの呼び出しが有効かどうかを自動的にチェックするのに役立つ手法があるかどうか。

AClass は、実際には私のプロジェクトのコンテキストでは API です。a()、b() などは、プログラマーが API を使用したい場合に呼び出すことができる関数ですが、これらのメソッドの一部は、正確な順序でしか呼び出すことができません。たとえば、コードで a() がモード = 1 に設定されていることがわかります。したがって、プログラマーは次のようにすることができます。

a(); // mode = 0 so it's good
b(); // mode = 1 so it's good

しかし、このコードは失敗する必要があります (もちろんコンパイルされますが、実行時に b() が呼び出されたコンテキストが間違っていたことを示すエラーをスローする必要があります。

b(); // mode 0 so it won't work
a(); // it will compile but throw an exception

これを行うために何らかのパターンが機能するかどうかを確認しようとしましたが、何も見つかりませんでした。私には不可能に思えますが、必要なコードを実際に書くことが唯一の選択肢だと思います。誰かが何かを提案できますか?どうもありがとうございました。

4

4 に答える 4

3

プライベート メンバー関数を追加するだけです。

void assert_mode_0() {
    assert_mode(0);
}

void assert_mode_1() {
    assert_mode(1);
}

void assert_mode(int m) {
    if (mode != m)
        throw msg[m];
}

もちろん、の適切な定義でmsg

于 2012-11-03T21:29:57.877 に答える
2

AClassチェックを専用のメソッドに実装する (素晴らしい提案) 以外に、動作を 2 つの異なるクラスに分解するか、特定の部分を新しいクラスのペアに委譲することも検討できます。modeこれは、 がインスタンスに対して不変である場合 (例のように) に特に適しているようです。

于 2012-11-03T21:31:54.250 に答える
0

最も簡単な解決策は、マクロまたは次のようなインライン関数を定義することだと思います。

#define checkErrorMode0(x) \
    if ((x) != 0) throw ("Error mode should be 0");
#define checkErrorMode1(x) \
    if ((x) != 1) throw ("Error mode should be 1");

// or, probably within your class
inline void checkErrorMode0(int x){
    if ( x != 0 ) throw ("Error mode should be 0");
}

inline void checkErrorMode1(int x){
    if ( x != 1 ) throw ("Error mode should be 1");
}

したがって、それらを必要とする関数内でこれらのメソッドの 1 つを呼び出すだけで済みます。

しかし、あなたがやりたいことに対するより洗練された回避策がある可能性が最も高いです。

于 2012-11-03T21:18:15.667 に答える
0

問題をもう少し詳しく調べたところ、最も役立つ答えは次のようです (by Nick):

Aspect Oriented Software Development en.wikipedia.org/wiki/Aspect-directional_software_development を調べてみてください – Nick

ウィキペディアのページは読みにくく、C++ の例を提供していないため、最初は非常に抽象的なままですが、Aspect Oriented Programming および C++ を検索すると、例のリンクが見つかります。

その背後にあるアイデア (および非常に簡単な要約) は、「サービス」または「機能」をクラスに追加する方法を見つけることです。これらのサービスは、特にテンプレートを使用してコンパイル時に追加できます。これは、問題を解決する試みとして私が直感的に実験していたものであり、この手法が何年も前から存在していることを嬉しく思います。

このドキュメントは良いリファレンスです:

アスペクト指向プログラミングと C++ Christopher Diggins 著、2004 年 8 月 1 日。

そして、概念を理解するのに役立つ例を含むこのリンクを見つけました:

Calum Grant によるジェネレーティブ プログラミングを使用したアスペクトの実装。

于 2012-11-04T11:29:19.493 に答える