我正在写一系列记录器。一个将写入控制台,一个写入stdout,一个写入专有文件格式。在任何时候,我都希望能够实现这些记录器并自行工作。
我原本打算使用装饰器模式将记录器堆叠在一起,但我意识到装饰器并不打算自己承担额外的责任。
所以我的问题: 1)责任能够独立生活是否可以接受? 2)装饰器模式仍然是正确的路径,还是有更好地适应我描述的问题的模式?
答案 0 :(得分:1)
我使用过伪C# - 如果您更喜欢其他语言,请告诉我。
要实现此目的,首先要创建一个日志记录界面。执行日志记录的任何对象都将遵循此:
public interface Logger
{
void Log(string message);
}
接下来,您将需要装饰器类,它将包装您的日志记录功能。如果您不希望人们直接实例化它,这也可能是抽象的。它接受一个记录器对象,并将所有日志消息代理到此:
public class LoggerDecorator : Logger
{
Logger logger;
public LoggerDecorator(Logger logger)
{
this.logger = logger;
}
public override void Log(string message)
{
logger.log(message);
}
}
可以创建独立记录器:
public class StdoutLogger : Logger
{
public override void Log(string message)
{
// Log message to stdout
}
}
或者“堆叠”记录器,只需使用decorator
:
public class FileAndStdoutLogger : LoggerDecorator
{
public FileAndStdoutLogger(Logger logger)
{
super(logger);
}
public void log(String message)
{
logger.log(msg);
// Log to file
}
}
然后您可以创建独立或装饰的记录器:
var stdoutLogger = new StdoutLogger();
stdoutLogger.log("This will log only to stdout");
// Will output "This will log only to stdout" to stdout
var fileAndStdoutLogger = new FileAndStdoutLogger(new StdoutLogger());
fileAndStdoutLogger.log("This will log to file & stdout");
// Will output "This will log to file & stdout" to file and stdout
如果您需要更多示例,请告知我们。
答案 1 :(得分:1)
我打算使用装饰器模式将记录器堆叠在顶部 彼此
我不认为这是个好主意。装饰者模式应该作为某种method call intercepcion或AOP。
这意味着在执行函数体之前和/或之后执行一些代码。正在筑巢。我不会嵌套我的伐木工;我不想让记录器取决于其他记录器。
一个好的策略是创建一个通用记录器并为其添加侦听器。每个监听器都有自己的策略来编写loged数据。就像.NET环境中的Trace and Debug一样。然后,您的通用记录器只需浏览添加的侦听器列表,并在每个侦听器上调用log(message)
。
然后应用装饰器模式来组合装饰服务,以解决日志和安全等交叉问题。
Public Interface IMyService{
int someAction();
}
Public Class MyService:IMyService{
int someAction(){//impl goes here}
}
Public Class SecureMyService:IMyService{
SecureMyService(IMyService innerService){
inner = innerService;
}
int someAction(){
if (!HasRights()) {throw authorizationException};
return inner.someAction();
}
}
Public Class LoggedMyService:IMyService{
SecureMyService(IMyService innerService){
inner = innerService;
}
int someAction(){
logger.log("invoking some Action");
return inner.someAction();
}
}
//resolve decorated service. A DI container does wonderful things for decorator pattern ;)
IMyService GetService(){
myService = new MyService();
mySecuredService = new SecureMyService(myService);
myLoggedAndSecuredService = new LoggedMyService(mySecuredService);
return myLoggedAndSecuredService;
}