在过去的几个月中,我一直要求SE和其他网站上的人员给我一些有关我的代码的建设性批评。一件事几乎每次都会弹出,我仍然不同意这个建议。:P我想在这里讨论它,也许事情对我来说会变得更加清楚。
它与单一责任原则(SRP)有关。基本上,我有一个数据类,Font
它不仅包含用于处理数据的函数,而且还用于加载数据。有人告诉我这两个应该分开,加载函数应该放在工厂类中。我认为这是对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
是自给自足的,因此经理不需要知道如何建立一个。相反,管理器确保同一文件或缓冲区不会多次加载到内存中。您可以说工厂可以做同样的事情,但这不会破坏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,但我想不到一个
。请发布您有的任何反论点,以及您认为建议的设计比我自己的设计有的优势。基本上,请告诉我我错了。:)