過去数か月、私はここSEや他のサイトの人々に、私のコードに関して建設的な批判をしてくれるように頼みました。ほぼ毎回飛び出し続けていることが1つあります。それでも、その推奨事項には同意しません。:P私はそれについてここで議論したいと思います、そして多分物事は私にとってより明確になるでしょう。
それは単一責任原則(SRP)に関するものです。基本的に、私はデータクラスを持っています。これは、データFont
を操作するための関数だけでなく、データをロードするための関数も保持しています。ロードファンクションはファクトリクラス内に配置する必要があると、2つは分離する必要があると言われています。これはSRPの誤解だと思います...
私のフォントクラスの一部
class Font
{
public:
bool isLoaded() const;
void loadFromFile(const std::string& file);
void loadFromMemory(const void* buffer, std::size_t size);
void free();
void some();
void another();
};
提案されたデザイン
class Font
{
public:
void some();
void another();
};
class FontFactory
{
public:
virtual std::unique_ptr<Font> createFromFile(...) = 0;
virtual std::unique_ptr<Font> createFromMemory(...) = 0;
};
提案された設計はSRPに従うと思われますが、私は同意しません—行き過ぎだと思います。Font
クラスは、長い自給自足(それは工場なしで無用である)ではない、そしてFontFactory
おそらく友情や更の実装を公開し、パブリックゲッター、を介して行われたリソースの実装の詳細を知っている必要がありますFont
。これはむしろ責任が分断されているケースだと思います。
これが私のアプローチの方が良いと思う理由です:
Font
は自給自足型—自給自足型であるため、理解と保守が容易です。また、他に何も含まなくてもクラスを使用できます。ただし、リソース(ファクトリ)のより複雑な管理が必要な場合は、簡単に行うこともできます(後で、自分のファクトリについて説明しますResourceManager<Font>
)。標準ライブラリに従います—ユーザー定義型は、それぞれの言語で標準型の動作をコピーするために、可能な限り試行する必要があると思います。
std::fstream
自己十分であり、それは次のような機能を提供open
してclose
。標準ライブラリに従うと、さらに別の方法で学習に労力を費やす必要がなくなります。その上、一般的に言えば、C ++標準委員会はおそらくここの誰よりもデザインについて知っているので、疑わしい場合は、彼らが行っていることをコピーします。テスト容易性—問題が発生した場合、どこに問題があるのでしょうか?—
Font
データを処理する方法FontFactory
ですか、それともデータをロードする方法ですか?あなたは本当に知りません。クラスを自己完結型にすることで、この問題が軽減されますFont
。独立してテストできます。その後、ファクトリをテストするFont
必要があり、正常に機能していることがわかっている場合は、問題が発生するたびにファクトリ内にある必要があることもわかります。それは文脈にとらわれない—(これは私の最初の点と少し交差します。)
Font
そのことを行い、それをどのように使用するかについての仮定はありません。好きな方法で使用できます。ユーザーにファクトリの使用を強制すると、クラス間の結合が増加します。
私にも工場があります
(のデザインFont
が私を可能にするので。)
あるいは、単なるファクトリでFont
はなく、マネージャの方が自給自足なので、マネージャは、どのようにビルドするかを知る必要はありません。代わりに、マネージャは同じファイルまたはバッファがメモリに2回以上ロードされないようにします。工場でも同じことができると言えるかもしれませんが、それはSRPを壊しませんか?ファクトリはオブジェクトを構築するだけでなく、それらを管理する必要もあります。
template<class T>
class ResourceManager
{
public:
ResourcePtr<T> acquire(const std::string& file);
ResourcePtr<T> acquire(const void* buffer, std::size_t size);
};
以下は、マネージャの使用方法のデモです。基本的にはファクトリーとまったく同じように使用されることに注意してください。
void test(ResourceManager<Font>* rm)
{
// The same file isn't loaded twice into memory.
// I can still have as many Fonts using that file as I want, though.
ResourcePtr<Font> font1 = rm->acquire("fonts/arial.ttf");
ResourcePtr<Font> font2 = rm->acquire("fonts/arial.ttf");
// Print something with the two fonts...
}
結論...
(ここにtl; drを入れたいのですが、思いつきません
。あなたが持っている反論や提案されたデザインが私自身のデザインよりも優れていると思われる利点があれば投稿してください。基本的に、私が間違っていることを見せてください。:)