为了为更大的应用程序创建日志系统,我提出了以下草案。日志接收器尚未详细说明,但用于创建记录器的工厂方法和记录器本身的粗略草案是。这是一个好的开始,值得继续下去吗?或者你能看到陷阱?
class LoggingSink; // abstract base class
class ConsoleSink : public LoggingSink; // some concrete logging sink
class LogfileSink : public LoggingSink; // ... too
/***********************************************/
class Logger {
public:
void log(const std::string& msg) {
for (LoggingSink ls : Sinks)
ls.log(msg);
}
private:
std::list<std::reference_wrapper<LoggingSink>> Sinks;
friend class LoggerFactory;
};
/***********************************************/
class LoggerFactory {
public:
std::unique_ptr<Logger> create() {
std::unique_ptr<Logger> result = std::make_unique<Logger>();
result->Sinks.assign(StandardAssignedSinks.begin(), StandardAssignedSinks.end());
return result;
}
void addStandardSink(LoggingSink& ls) {
Sinks.push_back(std::reference_wrapper<LoggingSink>(ls));
}
private:
std::list<std::reference_wrapper<LoggingSink>> StandardAssignedSinks;
};
/***********************************************/
int main() {
ConsoleSink cs;
LogfileSink lfs("mylogfile.txt");
LoggerFactory lf;
lf.addStandardSink(cs); // adding as reference for polymorphism
lf.addStandardSink(lfs); // perhaps the addition of some standard sinks should be done in the constructor of LoggerFactory???
std::unique_ptr<Logger> myLogger = lf.create();
myLogger->log("Hello Log, I'm going to be injected soon!");
MyClass myClassInstance(myLogger); // constructor dependency injection
MyClass myOtherInstance(lf.create()); // direct DI
}我也不确定朋友班的事。这是我从来不喜欢的工厂。有什么好办法吗?
发布于 2014-04-07 16:01:50
正如评论中指出的那样:
我会让工厂保留所有权:
class LoggerFactory {
typedef std::map<std::string, std::unique_ptr<Logger>> Container;
typedef Container::iterator iterator;
typedef Container::const_iterator const_iterator;
typedef Container::value_type value_type;
typedef std::list<std::reference_wrapper<LoggingSink>> SinkHolder;
public:
Logger& get(std::string const& loggerName = "default")
{
iterator find = cont.find(loggerName);
if (find == cont.end())
{
std::unique_ptr<Logger> result = std::make_unique<Logger>();
// Personally I would not do this.
// I would pass the iterators to the constructor
// of the Logger object.
result->Sinks.assign(std::begin(standardAssignedSinks),
std::end(standardAssignedSinks));
auto insertR = cont.insert(value_type(loggerName, result));
if (!insertR.second)
{ throw std::runtime_error("Insertion Failed");
}
find = insertR.first;
}
return *(find->second);
}
void addStandardSink(LoggingSink& ls) {
standardAssignedSinks.empace_back(ls);
}
private:
SinkHolder standardAssignedSinks;
Container cont;
};现在你可以有多个记录器了。但是您可以重用记录器(因为每个记录器都有自己的名称)。大多数情况下,人们应该使用默认的记录器。
构建流日志记录程序并不困难,它只是需要一个中间缓冲区对象来积累消息。当它被销毁时,它会向记录器发送消息。
class Logger {
public:
template<typename T>
LogStreamBuffer operator<<(T const& data) // Member so left hand side implied as Logger
{
// This is not perfect
// This may cause a copy (and thus a destruction)
// If there is a copy/destruction cycle an extra message will be
// sent. You can code around this problem.
// This is just to get you started.
return LogStreamBuffer(*this) << data;
}
// OTHER STUFF
};
class LogStreamBuffer
{
Logger& parent;
std::stringstream buffer;
public:
LogStreamBuffer(Logger& parent)
: parent()
{}
~LogStreamBuffer()
{
// When the object is destroyed.
// Log the accumulated message with the parent.
parent.log(buffer.str());
}
template<typename T>
LogStreamBuffer& operator<<(T const& data)
{
// Anything you log is just appended to the message.
buffer << data;
return *this; // return a reference to yourself.
// So you can chain messages.
}
};
// Usage:
int main()
{
LoggerFactory factory;
Logger logger = factory.get("MyLogger");
logger << "This is a test: " << 1 << " Got it";
// ^^^
// Creates a LogStreamBuffer
// As an invisable temporary object.
// The subsequent `operator<<` will accumulate
// data in the buffer. When the statement is
// finished (at the ;) all temporaies will be
// destroyed. This calls the LogStreamBuffer
// destructor and logs your data to the Logger
// object.
}https://codereview.stackexchange.com/questions/46499
复制相似问题