In object-oriented programming, the open/closed principle is a very important principle. Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. Recently I tried to summary some commonly used components in a serials of documents. I found that I have used delegate in my LogHelper class. This reminds me about my OCP.
I was not intended to use delegate as a way to extend my log feature. I was using it to avoid building a message string but not actually used for logging. I thought it will be nice to use a pointer to function which returns a string. So that the function would be called dynamically only if logging is enabled.
public delegate string GetMessage();
public static class LogHelper {
public void WriteMessage(
ILog log, string flag, GetMessage getMessage)
{
if (log != null && getMessage != null
&& log.IsLogSet(flag))
{
var msg = getMessage();
log.write(msg);
}
...
}
Here is an example of the usage:
LogHelper.WriteMessage(log, "d", delegate() {
return string.format("MyObject: {0}",
myObject.ToString());
};
As shown in above example, user can build a simple or complicated string for logging. Since the building codes are in a dynamic delegate. The delegate will only be called when the log flag "d" is enabled.
I think that my design of LogHelp class is a typical way to OCP. Here is another example to use the same method to enable indention and un-indention for messages:
class DataProcess {
private int m_indention = 0;
private void LogMsg(bool indent, GetMessage getMsg)
{
if ( getMsg == null )
{
return;
}
if (indent)
{
m_indention+= 2;
}
else if ( m_indention > 0 )
{
m_indention -= 2;
}
else
{
m_indention = 0;
}
LogHelper.WriteMessage(log, "d", delegate() {
return string.format("{0}MyObject: {1}",
new String(' ', m_indention),
getMsg());
};
}
...
}