微软常用的组件设计思想-‘工厂的工厂类’
微软常用的组件设计思想-‘工厂的工厂类’
我们在写代码的时候,经常碰到各种软件的设计思想,也许,你是一个弱小的码农,也逃不了设计的思想已悄悄的走向你的身边,只是我们不知道这叫啥罢了。
诸如,我们经常玩的三层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);
小结:设计的思想,就是从人的思想角度出发,驱动代码的构造。好的设计思想,往往都是从代码中提炼而来,从而推动了更优秀的设计思想,不断的创新迭出!
做为程序员多看看优质的源码,可以快速的吸收别人的精髓,这也是一种‘智取’。
转自:http://www.cnblogs.com/laogu2/p/5912153.html
在设计模式的教学和推广过程中,很多企业学员和在校学生经常问我,工厂模式(包括简单工厂模式、工厂方法模式和抽象工厂模式)到底有什么用,很多时候通过反射机制就可以很灵活地创建对象,为毛还要工厂?
,在本文中我将围绕创建对象和使用对象来简单谈谈工厂的作用。
与一个对象相关的职责通常有三类:对象本身所具有的职责、创建对象的职责和使用对象的职责。对象本身的职责比较容易理解,就是对象自身所具有的一些数据和行为,可通过一些公开的方法来实现它的职责。在本文中,我们将简单讨论一下对象的创建职责和使用职责。
在Java语言中,我们通常有以下几种创建对象的方式:
(1) 使用new关键字直接创建对象;
(2) 通过反射机制创建对象;
(3) 通过clone()方法创建对象;
(4) 通过工厂类创建对象。
毫无疑问,在客户端代码中直接使用new关键字是最简单的一种创建对象的方式,但是它的灵活性较差,下面通过一个简单的示例来加以说明:
- class LoginAction {
- private UserDAO udao;
- public LoginAction() {
- udao = new JDBCUserDAO(); //创建对象
- }
- public void execute() {
- //其他代码
- udao.findUserById(); //使用对象
- //其他代码
- }
- }
在LoginAction类中定义了一个UserDAO类型的对象udao,在LoginAction的构造函数中创建了JDBCUserDAO类型的udao对象,并在execute()方法中调用了udao对象的findUserById()方法,这段代码看上去并没有什么问题。下面我们来分析一下LoginAction和UserDAO之间的关系,LoginAction类负责创建了一个UserDAO子类的对象并使用UserDAO的方法来完成相应的业务处理,也就是说LoginAction即负责udao的创建又负责udao的使用,创建对象和使用对象的职责耦合在一起,这样的设计会导致一个很严重的问题:如果在LoginAction中希望能够使用UserDAO的另一个子类如HibernateUserDAO类型的对象,必须修改LoginAction类的源代码,违反了“开闭原则”。如何解决该问题?
最常用的一种解决方法是将udao对象的创建职责从LoginAction类中移除,在LoginAction类之外创建对象,那么谁来负责创建UserDAO对象呢?答案是:工厂类。通过引入工厂类,客户类(如LoginAction)不涉及对象的创建,对象的创建者也不会涉及对象的使用。引入工厂类UserDAOFactory之后的结构如图1所示:

图1 引入工厂类之后的结构图
工厂类的引入将降低因为产品或工厂类改变所造成的维护工作量。如果UserDAO的某个子类的构造函数发生改变或者要需要添加或移除不同的子类,只要维护UserDAOFactory的代码,而不会影响到LoginAction;如果UserDAO的接口发生改变,例如添加、移除方法或改变方法名,只需要修改LoginAction,不会给UserDAOFactory带来任何影响。
在所有的工厂模式中,我们都强调一点:两个类A和B之间的关系应该仅仅是A创建B或是A使用B,而不能两种关系都有。将对象的创建和使用分离,也使得系统更加符合“单一职责原则”,有利于对功能的复用和系统的维护。
此外,将对象的创建和使用分离还有一个好处:防止用来实例化一个类的数据和代码在多个类中到处都是,可以将有关创建的知识搬移到一个工厂类中,这在Joshua Kerievsky的《重构与模式》一书中有专门的一节来进行介绍。因为有时候我们创建一个对象不只是简单调用其构造函数,还需要设置一些参数,可能还需要配置环境,如果将这些代码散落在每一个创建对象的客户类中,势必会出现代码重复、创建蔓延的问题,而这些客户类其实无须承担对象的创建工作,它们只需使用已创建好的对象就可以了。此时,可以引入工厂类来封装对象的创建逻辑和客户代码的实例化/配置选项。
使用工厂类还有一个“不是特别明显的”优点,一个类可能拥有多个构造函数,而在Java、C#等语言中构造函数名字都与类名相同,客户端只能通过传入不同的参数来调用不同的构造函数创建对象,从构造函数和参数列表中也许大家根本不了解不同构造函数所构造的产品的差异。但如果将对象的创建过程封装在工厂类中,我们可以提供一系列名字完全不同的工厂方法,每一个工厂方法对应一个构造函数,客户端可以以一种更加可读、易懂的方式来创建对象,而且,从一组工厂方法中选择一个意义明确的工厂方法,比从一组名称相同参数不同的构造函数中选择一个构造函数要方便很多。如图2所示:

那么,有人可能会问,是否需要为设计中的每一个类都配备一个工厂类?答案是:具体情况具体分析。如果产品类很简单,而且不存在太多变数,其构造过程也很简单,此时无须为其提供工厂类,直接在使用之前实例化即可,例如Java语言中的String类,我们就无须为它专门提供一个StringFactory,这样做反而有点像杀鸡用牛刀,大材小用,而且会导致工厂泛滥,增加系统的复杂度。
转自:http://blog.csdn.net/lovelion/article/details/7523392


浙公网安备 33010602011771号