2

多くのパラメータを持つ複雑な構築プロセスを持つクラスがあります。複数のクライアントがこのクラスのオブジェクトを共有し、これらのクライアントパラメータの和集合を使用してクラスをインスタンス化します。したがって、これらの要件を格納し、さまざまなクライアントの要求の整合性をチェックし、クラスをインスタンス化するファクトリクラスがあります。

さらに、複数のクライアントが複数のファクトリに使用する共通の使用モデルのセット(またはパラメータのセット)があります。

たとえば、例を考えてみましょう。(実際のコードはC ++ですが、私の経験はPythonであるため、Pythonで擬似コードを作成します。はい、この例は実際にはそのままでは機能しないことを知っています。)

class Classroom:
    def __init__(self, room_size=None, n_desks=None, n_boards=None, 
                       n_books=None, has_globe=False, ... ):
        ...

class ClassroomFactory:
    def __init__(self):
        self._requirements = dict()

    def addRequirement(self, name, value):
        if name.startswith("n_"):
            self._requirements[name] = max(value, self._requirements.get(name, 0))
        ...

    def createClassroom(self):
        return Classroom(**self._requirements)


# instantiate the factory
factory = ClassroomFactory()

# "client 1" is a geography teaacher
factory.addRequirement("n_desks", 10)
factory.addRequirement("n_boards", 1)
factory.addRequirement("has_globe", True)

# "client 2" is a math teacher
factory.addRequirement("n_desks", 10)
factory.addRequirement("n_boards", 1)

# "client 3" is a after-school day-care
factory.addRequirement("room_size",  (20,20))
factory.addRequirement("has_carpet", True)

room = factory.createClassroom()

一般的な使用モデルは教師としてであり、10台の机とボードが必要です。これは、次のような非メンバー関数/デコレータによって最適に提供されると思います。

def makeTeacherRoom(factory):
    factory.addRequirement("n_desks", 10)
    factory.addRequirement("n_boards", 1)        
    return factory

これは、「メンバーよりも非メンバー/非友人を優先する」パラダイムの優れた例のようです。

私が苦労しているのは、はるかに大きなオブジェクト指向コードのフレームワーク内で、名前空間と実際のファイルの両方の観点から、これらのタイプの非メンバー関数/デコレーターはどこに存在する必要があるかということです。

  1. それらはファクトリのファイル/名前空間に存在する必要がありますか?これらは工場と密接な関係がありますが、一般的な工場の制限であり、工場を使用するために使用する必要はありません。

  2. それらはクライアントのファイル/名前空間に存在する必要がありますか?クライアントはこれらの使用モデルを理解していますが、これにより複数のクライアント間での再利用が制限されます。

  3. クライアントの共通の基本クラスと一緒に住んでいる場合(たとえば、MathTeacherとGeographyTeacherによって継承される非メンバー関数makeTeacherRoom()も提供する「教師」クラス/名前空間を想像できます。

  4. 「utils」ファイルで、完全に別の場所に住む必要がありますか?もしそうなら、どの名前空間で?

4

3 に答える 3

1

これは主に個人的な決定です。ほとんどのオプションには、技術的な悪影響はありません。例えば:

  1. 使用の局所性のために、それらは可能でしたが、それは必要ではありません。
  2. データの局所性のために、それらは可能でしたが、再び...
  3. 彼らはそうすることができましたが、これは物事を少し厄介にする可能性があるようです。ユーティリティクラスを作成すると、それらを継承するか、後でオーバーライドするためにパーツを仮想化する必要がある場合があります。これにより、醜くなります。
  4. これは私の個人的なお気に入り、またはこれの変形です。

私は通常、適切な名前のutilファイル(または静的メソッドを持つクラス)を作成し、それを使用するクラス(mutilateのより便利なバージョン)と同じ名前空間に配置します。Education::Teacherクラスの場合、をEducation::TeacherUtils操作する関数を含むファイルまたはクラスを作成できますTeacher。これにより、かなり明白な名前付けの結びつきが維持されますが、util関数が独自の領域に配置されるため、必要なものからそれらを含めることができます(Teacher.cppまたは同様のものでそれを防ぐことができます)。クラスの場合、utilクラスとbaseクラスを友達にすることができます。これは時々役に立ちます(ただし、匂いがする可能性があるため、めったに使用しないものです)。

名前のバリエーションを見てきましたが、ファイルに変換するのはやや難しく( dirEducation::Utils::Teacherに入れない限り)、名前解決がおかしくなる可能性もあります(状況によっては、コンパイラが使用しなかった場合の代わりに使用しようとする場合があります)。 tは意味します)。このため、私は接尾辞として保持することを好みます。utilsEducation::Utils::TeacherEducation::Teacherutils

于 2012-06-26T18:14:20.463 に答える
0

アプリケーションのシングルトンクラスで非メンバー関数を処理することをお勧めします。ファクトリは、プログラムまたは別のオブジェクトから実行される可能性があります。

C ++はグローバル関数(非メンバー関数)をサポートしますが、アプリケーションに単一のオブジェクトを使用すると、「トリックを実行」します。

さらに、「Classroom」オブジェクトは多くのオプションのパラメーターでインスタンス化される可能性があるため、コンストラクター(pythonでは「 init 」)を呼び出した後に割り当てることができます。

// filename: "classrooms.cpp"

class ClassroomClass
{
  protected:
    int _Room_Size;
    int _N_Desks;
    int _N_Boards;
    int _N_Books;
    bool _Has_Globe;

  public:
    // constructor without parameters,
    // but, can be declared with them
    ClassroomClass()
    {
      _Room_Size = 0;
      _N_Desks = 0;
      _N_Boards = 0;
      _N_Books = 0;
      _Has_Globe = false;
    } // ClassroomClass()

    public int get_Room_Size()
    {
      return _Room_Size;
    }

    public void set_Room_Size(int Value)
    {
      _Room_Size = Value;
    }

    // other "getters" & "setters" functions
    // ...

} // class ClassroomClass

class ClassroomFactoryClass
{
  public:
    void addRequirement(char[] AKey, char[] AValue);
} // class ClassroomFactoryClass    

class MyProgramClass
{
  public:
    ClassroomFactoryClass Factory;
  public:
    void makeTeacherRoom();

    void doSomething();
} // class MyProgramClass

void MyProgramClass::addRequirement(char[] AKey, char[] AValue)
{
  ...
}  // void MyProgramClass::addRequirement(...)

void MyProgramClass::makeTeacherRoom()
{
  Factory.addRequirement("n_desks", "10")
  Factory.addRequirement("n_boards", "1")   
}  // void MyProgramClass::makeTeacherRoom(...)

void MyProgramClass::doSomething()
{
  ...
}  // void MyProgramClass::doSomething(...)

int main(char[][] args)
{
   MyProgramClass MyProgram = new MyProgramClass();

   MyProgram->doSomething();

   delete MyProgram();

  return 0;
}  // main(...)

乾杯

于 2012-06-26T23:30:09.687 に答える
0

個人的には、それらをクラスの静的メンバーにします。

class File
{
    public:

    static bool load( File & file, std::string const & fileName );

    private:

    std::vector< char > data;
};

int main( void )
{
    std::string fileName = "foo.txt";
    File myFile;

    File::load( myFile, fileName );
}

静的メソッドを使用すると、クラスの特定のインスタンスに属していない間、クラスのプライベートデータにアクセスできます。また、メソッドをユーティリティヘッダーのどこかに配置した場合のように、メソッドが作用するデータから分離されていないことも意味します。

于 2012-06-27T01:27:54.857 に答える