C/C++で趣味でやっています。
PCが一度ダメになったので C++用ライブラリを最初から作りなおしています。
Windows API を実装したときに LoadLibrary関数とかで DLLを動的リンクすることありますよね。
その場合の ライブラリを作ろうとしています。
今までは UML風に書くと
[ CDynamicLinkLibrary ] + CONSTRUCTOR( path : const std::string ) throw(例外) // LoadLibraryでリンクし、失敗すれば例外を投げる + DESTRUCTOR() // FreeLibraryで破棄 + Call( funcname : const std::string ) : FARPROC throw(例外) // DLL内の 関数ポインタを取得 + CallCusror( cursorId : int ) : HCURSOR // リソースDLLから 指定IDのカーソルを取得 + CallBitmap( bitmapId : int ) : HBITMAP // リソースDLLから 指定ビットマップを取得 + Play( soundId : int ) : bool // リソースDLLから指定IDの音声を再生する ... - hModule : HMODULE - filename : std::string
としていました。
( つまり、DLLからの取得等は この CDynamicLinkLibrary に任せるっていう... )
ですがPCがダメになったのでその中にあったデータもダメになったため、再度作ることにしました。
これを機に、namespaceに包んだりして もうちょっと C++らしくしようとしています。
で、今イメージしているのは2種類です。
方法1:
namespace LibraryLoader内に CDynamicLinkLibraryクラス ( ただし、DLLのリンクと 破棄, getHandle のみ。構造体にコンストラクタ・デストラクタがついたようなクラス )を追加し、
CFunctionLinkerクラス, CCursorLinkerクラス... という風に処理ごとに分割。( 関数オブジェクト )
それぞれ CDynamicLinkLibraryクラスをコンポジションする。
C++
1// throw(例外) とある部分は std::exception を継承した例外クラスだとします。(例なので) 2namespace LibraryLoader{ 3 4 // cppファイルに書いて隠ぺいする (外部に触らせないために) 5 class CDynamicLinkLibrary{ 6 public: 7 CDynamicLinkLibrary( const std::string filename ) throw(例外); 8 ~CDynamicLinkLibrary(); 9 10 getHandle(void){ return this->hModule; } 11 private: 12 HMODULE hModule; 13 ... 14 }; 15 16 // 以降はヘッダファイルにクラス定義をして外部へ公開する ( 前方宣言付き ) 17 class CFunctionLinker{ 18 public: 19 CFunctionLinker( const std::string filename ) throw(例外){ 20 dll = new CDynamicLinkLibrary( filename ); 21 } 22 23 ~CFunctionLinker(){ delete dll; } 24 25 FARPROC operator()( const std::string funcname ){ 26 HMODULE module = dll->getHandle(); 27 // ここで HMODULE から 関数ポインタを取得する 28 } 29 private: 30 CDynamicLinkLibrary* dll; 31 }; 32 33 class CCursorLinker{ 34 public: 35 CCursorLinker( const std::string filename ) throw(例外){ 36 dll = new CDynamicLinkLibrary( filename ); 37 } 38 39 ~CCursorLinker(){ delete dll; } 40 41 FARPROC operator()( const std::string funcname ){ 42 HMODULE module = dll->getHandle(); 43 // ここで HMODULE から カーソルを取得する 44 } 45 private: 46 CDynamicLinkLibrary* dll; 47 }; 48 ... 49}
方法2:
従来のやり方 ( 上記のUML風のやつ ) を namespace LibraryLoader で包んだだけ。
どれが C++ として正しいのかがわかりません。
動く・動かない ( または コンパイルが通る・通らない ) は実際に試せばいいかもしれませんが、
こういうのは慣れとかだと思うので。
自分なりに デザインパターン ( といっても ちょっとだけ。 Factory, TemplateMethod, Strategy ... となんとなく使えそうなやつだけ ) やったり、
UML を解説してるサイトをなるべく読んだり,
自分なりに組んだりしているのですが...
なぜ 方法1 のように考えたかというと、
2chだったか、何でだったか忘れましたが、「それ オブジェクト指向の原則からしたらダメじゃねーか!」みたいな文章があったので、
「ああ、オブジェクト指向に『原則』ってあるんだな」と思い、
検索したところ、
単一責任の原則 ( SRP原則 ) というらしいですね。
まだ詳しくはチェックしていませんが、
「クラスを変更する理由が2つ以上存在してはならない」というやつらしいです。
それで、そういうことを紹介している記事にちょいちょい「リファクタリング」というものが出てきます。
主に Javaでの説明が多いですが、
リファクタリングしてみよう2の「フィールドの引き上げ(320)」で
フィールドの名前が違う場合、スーパークラスのフィールドとして使いたい名前に変更する コンパイルしてテストする スーパークラスに新しいフィールドを作成する =>フィールドがprivateならば、サブクラスから参照できるようにprotectedに変更する サブクラスのフィールドを削除する コンパイルしてテストする そのフィールドに対して「自己カプセル化フィールド(171)」の適用を検討する
(上記ページより)
とあったので方法1を思いつきました。
ですが こういうのは条件 ( 状況とか ) によって変わりますよね。
やたらめったら Singletonパターンを適用するのはダメだし... とか。
今回の場合はどうやれば(オブジェクト指向的に)正解なのでしょうか。
やるからには出来る限り そういう原則とかを守りたいので。
言語は上記の通り C++ でお願いします。
宜しくお願い致します。
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。