- ベストアンサー
クラスの設計について
例えば、システムAPIのパラメータを保持しているクラスは、カプセル化という点でAPIの呼び出しまで行ったほうが良いのでしょうか?(処理を任せる) getParam()などでパラメータを取得する形にしてしまうと戻り値が具体的な型になってしまい、 抽象化しづらくなってしまいます。 もちろんケースバイケースなのかもしれないですが。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
もう、解決済みかもしれませんが、僕はクラスの設計をするとき 処理とデータと操作(ユーティリティ)は、極力分離するようにしています。 んで、この考え方で行くと質問の内容は、 システムAPIのパラメータを保持しているデータ用のクラスにAPI呼び出しによる処理をさせようとしているように思えますので、僕なら逆にしますね。 つまり、APIの呼び出しを行うクラスにパラメータを保持しているデータ用のクラスを指定する形でしょうか。 パラメータを保持するクラスというのがコンフィグ系であるのなら、 関数のパラメータに指定するよりも、コンポジットさせてしまってFactory関数をオーバーライドするかな~? class hoge_base { CONFIG *config; virtual int initConfig() = 0; }
その他の回答 (5)
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
No.3 です。 補足をいただいたようですが、 > もちろん、場合によっては、特に低レベルなクラスでは「それではやっていけない」場合もあります。 > その場合でも、この基本を意識して、「なぜ、基本を外さなければならないのか」が説明できなければ、どこかおかしい可能性が高いです。 というのをご理解いただいた上での補足でしょうか? さて、抽象化できると言うことは、本来、「同じものだと見なせる」ということです。 似ているというだけではなく、「どういう観点から同じものだと見なしたか」という説明ができなければ、似ていると思い込んで強引に継承をしている可能性が高いと言うことです。 よくあるのが、タイヤから自転車と自動車をそれぞれ継承したりするミスです。 自転車は、タイヤではなく、「タイヤを持っている」のです。 こういう点を考える価値はあります。
- shiren2
- ベストアンサー率47% (139/295)
個人的には、クラスは機能単位で分離することが望ましいと思います。 そもそもAPIのパラメータを返すだけのクラスはOOP的ではなく、継ぎ接ぎという印象が拭えません。 それならFactory Methodパターンを検討するべきだと思います。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
補足のコードが一向に具体的でない気がしますが。 それはさておき、基本は ・同じ基底クラスから派生した二つのクラスが、別々のパブリックメンバーを持っているのはどこかおかしい。 ・使う方がダウンキャストをしなければならないシステムはどこかおかしい。 です。 もちろん、場合によっては、特に低レベルなクラスでは「それではやっていけない」場合もあります。 その場合でも、この基本を意識して、「なぜ、基本を外さなければならないのか」が説明できなければ、どこかおかしい可能性が高いです。 もうひとつ言えば、一連の(同レベルの)クラス群だけでAPIを扱おうと思うと、設計が破綻することがあります。 その場合、いくつかの層に分けてクラスを構成すると、うまく設計ができる場合があります。 または、全体は抽象レベルを上げて設計をしておいて、どうしても、「土足で立ち入る」必要が出てきたときのために、内部をアクセスするためのクラス群を、別立てで準備することもあります。 (そのためにも、friend という機能がある)
補足
回答ありがとうございます。 >>・同じ基底クラスから派生した二つのクラスが、別々のパブリックメンバーを持っているのはどこかおかしい。 つまり最終的に使用するデータが異なる場合は似たクラスであったも抽象化できないということでしょうか?
- D-Matsu
- ベストアンサー率45% (1080/2394)
Param1/Param2が構造体でAPIのバージョン違いという話なら…… class hoge { public: virtual int getVersion() = 0; virtual bool getParam(void *) = 0; }; class hoge1 : virtual hoge { Param1 param; public: int getVersion(){ return 1; } bool getParam(void *p){ static_cast<Param1>(*p) = param; return true; } }; (以下hoge2も同様) ってな感じにしておいて、getVersion()の戻り値でgetParamの引数を切り替える感じにすればそれなりに抽象化できるかと思います。 まぁParam1/2自体を共通のベースクラスを持つクラス化してgetParamの戻り値をベースクラスにするなんて手も考えられますが、これはParam1/2にある程度の互換がないと色々面倒ではあります。
- D-Matsu
- ベストアンサー率45% (1080/2394)
「パラメータ」は通常具体的な型にまで落ちてるものじゃありませんか? パブリッククラスメンバ変数だって具体的な型になっているのには変わりない訳で、何を問題視しているのかが今一つ質問だけでは見えないんですが……
補足
回答ありがとうございます。 質問がわかりづらくて申し訳ありません。 例えばAPIのバージョン毎にクラスを用意する場合、 class Hoge { }; class Hoge1 : public Hoge { Param1 param; Param1 getParam(); }; class Hoge2 : public Hoge { Param2 param; Param2 getParam(); }; 使う側がダウンキャストしてサブクラスを取得するよりはAPIの呼び出しを任せてしまったほうが良いものなのかわからなくて質問しました。
補足
回答ありがとうございます。 パラメータを返すだけ無くそれぞれのシステムにあったパラメータの操作も行います。