我們在寫代碼的時候,經常碰到各種軟件的設計思想,也許,你是一個弱小的碼農,也逃不了設計的思想已悄悄的走向你的身邊,只是我們不知道這叫啥罷了。
諸如,我們經常玩的三層BLL DAL UI 那麼還有一個東東,就是工廠Factory起到橋接作用。
回憶起三層,Factory 是一種設計模式
工廠方法模式的結構圖如下:

Product定義了工廠方法所創建的對象的接口。
ConcreteProduct實現Product接口, 定義了具體對象。
Creator定義了具體對象創建的工廠方法,該方法返回一個Product類型的對象。Creator也可以定義一個工廠方法的缺省實現,它返回一個缺省的ConcreteProduct對象
ConcreteCreator實現Creator接口,重定義工廠方法以返回一個ConcreteProduct實例。
示例
我們以實現一個文檔處理系統來看一下工廠方法模式的應用。
首先定義文檔類型的接口和兩個具體的文檔類型
1 public interface IFile
2 {
3 void New();
4 void Save();
5 }
6 public class DocFile : IFile
7 {
8 public void New()
9 {
10 Console.WriteLine("New Doc Create");
11 }
12 public void Save()
13 {
14 Console.WriteLine("Save Doc");
15 }
16 }
17 public class TxtFile : IFile
18 {
19 public void New()
20 {
21 Console.WriteLine("New Txt Create");
22 }
23 public void Save()
24 {
25 Console.WriteLine("Save Txt");
26 }
27 }
接著實現對象創建的工廠方法及具體文檔的創建工廠
1 interface IFileFactory
2 {
3 IFile Create();
4 }
5 public class DocFileFactory : IFileFactory
6 {
7 public IFile Create()
8 {
9 return new DocFile();
10 }
11 }
12 public class TxtFileFactory : IFileFactory
13 {
14 public IFile Create()
15 {
16 return new TxtFile();
17 }
18 }
最後看一下如何調用
1 static void Main(string[] args)
2 {
3 IFile docFile = (new DocFileFactory()).Create();
4 docFile.New();
5 docFile.Save();
6 IFile txtFile = (new TxtFileFactory()).Create();
7 txtFile.New();
8 txtFile.Save();
9 Console.ReadLine();
10 }
回憶到此,想必,大家對工廠有個很好的體會了,不過,今天,我們看看微軟是如何在工廠的基礎上動手腳的

上圖是微軟最喜歡用的工廠設計模式思想(此例為日志工廠)。
我們來分析上面的思路
1)為了能夠使程序在加載的時候,動態適應改變不同的工廠,而引入了LoggerFactory工廠類
2)減輕了每次在代碼中去重復的指定工廠實現類
3)上圖中,第一步通過LoggerFactory工廠類SetCurrent()指定當前工廠實現類TraceSourceLogFactory
4) LoggerFactory工廠類調用方法CreateLog()直接調用TraceSourceLogFactory工廠類Create(),進而創建出TraceSourceLog 現實類
我們來看看具體的代碼:
1)ILogger接口:
public interface ILogger
{
/// <summary>
/// Log debug message
/// </summary>
/// <param name="message">The debug message</param>
/// <param name="args">the message argument values</param>
void Debug(string message, params object[] args);
/// <summary>
/// Log debug message
/// </summary>
/// <param name="message">The message</param>
/// <param name="exception">Exception to write in debug message</param>
void Debug(string message,Exception exception,params object[] args);
/// <summary>
/// Log debug message
/// </summary>
/// <param name="item">The item with information to write in debug</param>
void Debug(object item);
/// <summary>
/// Log FATAL error
/// </summary>
/// <param name="message">The message of fatal error</param>
/// <param name="args">The argument values of message</param>
void Fatal(string message, params object[] args);
/// <summary>
/// log FATAL error
/// </summary>
/// <param name="message">The message of fatal error</param>
/// <param name="exception">The exception to write in this fatal message</param>
void Fatal(string message, Exception exception,params object[] args);
/// <summary>
/// Log message information
/// </summary>
/// <param name="message">The information message to write</param>
/// <param name="args">The arguments values</param>
void LogInfo(string message, params object[] args);
/// <summary>
/// Log warning message
/// </summary>
/// <param name="message">The warning message to write</param>
/// <param name="args">The argument values</param>
void LogWarning(string message, params object[] args);
/// <summary>
/// Log error message
/// </summary>
/// <param name="message">The error message to write</param>
/// <param name="args">The arguments values</param>
void LogError(string message, params object[] args);
/// <summary>
/// Log error message
/// </summary>
/// <param name="message">The error message to write</param>
/// <param name="exception">The exception associated with this error</param>
/// <param name="args">The arguments values</param>
void LogError(string message, Exception exception, params object[] args);
}
2)日志接口TraceSourceLog實現類:
public sealed class TraceSourceLog
:ILogger
{
#region Members
TraceSource source;
#endregion
#region Constructor
/// <summary>
/// Create a new instance of this trace manager
/// </summary>
public TraceSourceLog()
{
// Create default source
source = new TraceSource("NLayerApp");
}
#endregion
#region Private Methods
/// <summary>
/// Trace internal message in configured listeners
/// </summary>
/// <param name="eventType">Event type to trace</param>
/// <param name="message">Message of event</param>
void TraceInternal(TraceEventType eventType, string message)
{
if (source != null)
{
try
{
source.TraceEvent(eventType, (int)eventType, message);
}
catch (SecurityException)
{
//Cannot access to file listener or cannot have
//privileges to write in event log etc...
}
}
}
#endregion
#region ILogger Members
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="args"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void LogInfo(string message, params object[] args)
{
if (!String.IsNullOrWhiteSpace(message))
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
TraceInternal(TraceEventType.Information, messageToTrace);
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="args"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void LogWarning(string message, params object[] args)
{
if (!String.IsNullOrWhiteSpace(message))
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
TraceInternal(TraceEventType.Warning, messageToTrace);
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="args"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void LogError(string message, params object[] args)
{
if (!String.IsNullOrWhiteSpace(message))
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
TraceInternal(TraceEventType.Error, messageToTrace);
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="exception"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="args"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void LogError(string message, Exception exception, params object[] args)
{
if (!String.IsNullOrWhiteSpace(message)
&&
exception != null)
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
var exceptionData = exception.ToString(); // The ToString() create a string representation of the current exception
TraceInternal(TraceEventType.Error, string.Format(CultureInfo.InvariantCulture, "{0} Exception:{1}", messageToTrace, exceptionData));
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="args"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void Debug(string message, params object[] args)
{
if (!String.IsNullOrWhiteSpace(message))
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
TraceInternal(TraceEventType.Verbose, messageToTrace);
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="exception"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="args"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void Debug(string message, Exception exception,params object[] args)
{
if (!String.IsNullOrWhiteSpace(message)
&&
exception != null)
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
var exceptionData = exception.ToString(); // The ToString() create a string representation of the current exception
TraceInternal(TraceEventType.Error, string.Format(CultureInfo.InvariantCulture, "{0} Exception:{1}", messageToTrace, exceptionData));
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="item"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void Debug(object item)
{
if (item != null)
{
TraceInternal(TraceEventType.Verbose, item.ToString());
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="args"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void Fatal(string message, params object[] args)
{
if (!String.IsNullOrWhiteSpace(message))
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
TraceInternal(TraceEventType.Critical, messageToTrace);
}
}
/// <summary>
/// <see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/>
/// </summary>
/// <param name="message"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
/// <param name="exception"><see cref="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILogger"/></param>
public void Fatal(string message, Exception exception,params object[] args)
{
if (!String.IsNullOrWhiteSpace(message)
&&
exception != null)
{
var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, args);
var exceptionData = exception.ToString(); // The ToString() create a string representation of the current exception
TraceInternal(TraceEventType.Critical, string.Format(CultureInfo.InvariantCulture, "{0} Exception:{1}", messageToTrace, exceptionData));
}
}
#endregion
}
3) ILoggerFactory接口:
/// <summary>
/// Base contract for Log abstract factory
/// </summary>
public interface ILoggerFactory
{
/// <summary>
/// Create a new ILog
/// </summary>
/// <returns>The ILog created</returns>
ILogger Create();
}
4)TraceSourceLogFactory 接口ILoggerFactory實現類
/// <summary>
/// A Trace Source base, log factory
/// </summary>
public class TraceSourceLogFactory
:ILoggerFactory
{
/// <summary>
/// Create the trace source log
/// </summary>
/// <returns>New ILog based on Trace Source infrastructure</returns>
public ILogger Create()
{
return new TraceSourceLog();
}
}
5)LoggerFactory 工廠類
/// <summary>
/// Log Factory
/// </summary>
public static class LoggerFactory
{
#region Members
static ILoggerFactory _currentLogFactory = null;
#endregion
#region Public Methods
/// <summary>
/// Set the log factory to use
/// </summary>
/// <param name="logFactory">Log factory to use</param>
public static void SetCurrent(ILoggerFactory logFactory)
{
_currentLogFactory = logFactory;
}
/// <summary>
/// Createt a new <paramref name="Microsoft.Samples.NLayerApp.Infrastructure.Crosscutting.Logging.ILog"/>
/// </summary>
/// <returns>Created ILog</returns>
public static ILogger CreateLog()
{
return (_currentLogFactory != null) ? _currentLogFactory.Create() : null;
}
#endregion
}
在全局的項目配置裡加入設置當前工廠方法

細心的朋友可以看出,下面還有其它類似的工廠,哈哈,換湯不換藥。
調用: LoggerFactory.CreateLog().LogError(Messages.error_CannotPerformTransferInvalidAccounts);
小結:設計的思想,就是從人的思想角度出發,驅動代碼的構造。好的設計思想,往往都是從代碼中提煉而來,從而推動了更優秀的設計思想,不斷的創新迭出!
做為程序員多看看優質的源碼,可以快速的吸收別人的精髓,這也是一種‘智取’。
作者:谷歌's(谷歌's博客園)