.NET设计模式(5):工厂方法模式(Factory Method)

 

工厂方法模式(Factory Method

——.NET设计模式系列之五

Terrylee200412

概述

在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就是要说的Factory Method模式了。

意图

定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

结构图

生活中的例子

工厂方法定义一个用于创建对象的接口,但是让子类决定实例化哪个类。压注成型演示了这种模式。塑料玩具制造商加工塑料粉,将塑料注入到希望形状的模具中。玩具的类别(车,人物等等)是由模具决定的。

工厂方法解说

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。在Factory Method模式中,工厂类与产品类往往具有平行的等级结构,它们之间一一对应。

现在我们考虑一个日志记录的例子(这里我们只是为了说明Factory Method模式,实际项目中的日志记录不会这么去做,也要比这复杂一些)。假定我们要设计日志记录的类,支持记录的方法有FileLogEventLog两种方式。在这里我们先不谈设计模式,那么这个日志记录的类就很好实现了:

 1/// <summary>
 2/// 日志记录类
 3/// </summary>

 4public class Log
 5    {
 6
 7        public void WriteEvent()
 8        {
 9            Console.WriteLine("EventLog Success!");
10        }

11    
12        public void WriteFile()
13        {
14            Console.WriteLine("FileLog Success!");
15        }

16
17        public void Write(string LogType)
18        {
19            switch(LogType.ToLower())
20            {
21                case "event":
22                    WriteEvent();
23                    break;
24
25                case "file":
26                    WriteFile();
27                    break;
28
29                default:
30                    break;
31            }

32        }

33    }

34

这样的程序结构显然不能符合我们的要求,如果我们增加一种新的日志记录的方式DatabaseLog,那就要修改Log类,随着记录方式的变化,switch语句在不断的变化,这样就引起了整个应用程序的不稳定,进一步分析上面的代码,发现对于EventLogFileLog是两种完全不同的记录方式,它们之间不应该存在必然的联系,而应该把它们分别作为单独的对象来对待。

 1/// <summary>
 2/// EventLog类
 3/// </summary>

 4public class EventLog
 5{
 6    public void Write()
 7    {
 8        Console.WriteLine("EventLog Write Success!");
 9    }

10}

11
12/// <summary>
13/// FileLog类
14/// </summary>

15public class FileLog
16{
17    public void Write()
18    {
19        Console.WriteLine("FileLog Write Success!");
20    }

21}

22

进一步抽象,为它们抽象出一个共同的父类,结构图如下:

实现代码:

1/// <summary>
2/// Log类
3/// </summary>

4public abstract class Log
5{
6    public abstract void Write();
7}

8

此时EventLogFileLog类的代码应该如下:

 1/// <summary>
 2/// EventLog类
 3/// </summary>

 4public class EventLog:Log
 5{
 6    public override void Write()
 7    {
 8        Console.WriteLine("EventLog Write Success!");
 9    }

10}

11/// <summary>
12/// FileLog类
13/// </summary>

14public class FileLog:Log
15{
16    public override void Write()
17    {
18        Console.WriteLine("FileLog Write Success!");
19    }

20}

21

此时我们再看增加新的记录日志方式DatabaseLog的时候,需要做哪些事情?只需要增加一个继承父类Log的子类来实现,而无需再去修改EventLogFileLog类,这样的设计满足了类之间的层次关系,又很好的符合了面向对象设计中的单一职责原则,每一个类都只负责一件具体的事情。到这里似乎我们的设计很完美了,事实上我们还没有看客户程序如何去调用。 在应用程序中,我们要使用某一种日志记录方式,也许会用到如下这样的语句:

EventLog eventlog = new EventLog();
eventlog.Write();

当日志记录的方式从EventLog变化为FileLog,我们就得修改所有程序代码中出现上面语句的部分,这样的工作量是可想而知的。此时就需要解耦具体的日志记录方式和应用程序。这就要引入Factory Method模式了,每一个日志记录的对象就是工厂所生成的产品,既然有两种记录方式,那就需要两个不同的工厂去生产了,代码如下:

 1/// <summary>
 2/// EventFactory类
 3/// </summary>

 4public class EventFactory
 5{
 6    public EventLog Create()
 7    {
 8        return new EventLog();
 9    }

10}

11/// <summary>
12/// FileFactory类
13/// </summary>

14public class FileFactory
15{
16    public FileLog Create()
17    {
18        return new FileLog();
19    }

20}

21

这两个工厂和具体的产品之间是平行的结构,并一一对应,并在它们的基础上抽象出一个公用的接口,结构图如下:

实现代码如下:

1/// <summary>
2/// LogFactory类
3/// </summary>

4public abstract class LogFactory
5{
6    public abstract Log Create();
7}

8

此时两个具体工厂的代码应该如下:

 1/// <summary>
 2/// EventFactory类
 3/// </summary>

 4public class EventFactory:LogFactory
 5{
 6    public override EventLog Create()
 7    {
 8        return new EventLog();
 9    }

10}

11/// <summary>
12/// FileFactory类
13/// </summary>

14public class FileFactory:LogFactory
15{
16    public override FileLog Create()
17    {
18        return new FileLog();
19    }

20}

21

这样通过工厂方法模式我们把上面那对象创建工作封装在了工厂中,此时我们似乎完成了整个Factory Method的过程。这样达到了我们应用程序和具体日志记录对象之间解耦的目的了吗?看一下此时客户端程序代码:

 1/// <summary>
 2/// App类
 3/// </summary>

 4public class App
 5{
 6    public static void Main(string[] args)
 7    {
 8        LogFactory factory = new EventFactory();
 9
10        Log log = factory.Create();
11
12        log.Write();
13    }

14}

15

在客户程序中,我们有效地避免了具体产品对象和应用程序之间的耦合,可是我们也看到,增加了具体工厂对象和应用程序之间的耦合。那这样究竟带来什么好处呢?我们知道,在应用程序中,Log对象的创建是频繁的,在这里我们可以把

LogFactory factory = new EventFactory();

这句话放在一个类模块中,任何需要用到Log对象的地方仍然不变。要是换一种日志记录方式,只要修改一处为:

LogFactory factory = new FileFactory();

其余的任何地方我们都不需要去修改。有人会说那还是修改代码,其实在开发中我们很难避免修改,但是我们可以尽量做到只修改一处。

其实利用.NET的特性,我们可以避免这种不必要的修改。下面我们利用.NET中的反射机制来进一步修改我们的程序,这时就要用到配置文件了,如果我们想使用哪一种日志记录方式,则在相应的配置文件中设置如下:

1<appSettings>
2    <add key="factoryName" value="EventFactory"></add>
3</appSettings>
4

此时客户端代码如下:

 1/// <summary>
 2/// App类
 3/// </summary>

 4public class App
 5{
 6    public static void Main(string[] args)
 7    {
 8        string strfactoryName = ConfigurationSettings.AppSettings["factoryName"];
 9        
10        LogFactory factory;
11        factory = (LogFactory)Assembly.Load("FactoryMethod").CreateInstance("FactoryMethod." + strfactoryName);
12
13        Log log = factory.Create();
14        log.Write();
15    }

16}

17

现在我们看到,在引进新产品(日志记录方式)的情况下,我们并不需要去修改工厂类,而只是增加新的产品类和新的工厂类(注意:这是任何时候都不能避免的),这样很好的符合了开放封闭原则。

ASP.NET HTTP通道中的应用

Factory Method模式在ASP.NET HTTP通道中我们可以找到很多的例子。ASP.NET HTTP通道是System.Web命名空间下的一个类,WEB Server使用该类处理接收到的HTTP请求,并给客户端发送响应。HTTP通道主要的工作有Session管理,应用程序池管理,缓存管理,安全等。

System.Web.HttpApplicationFactory

HttpRuntimeHTTP通道的入口点,它根据每一个具体的请求创建一个HttpContext实例, HttpRuntime并没有确定它将要处理请求的HttpApplication对象的类型,它调用了一个静态的工厂方法HttpApplicationFactory.GetApplicationInstance,通过它来创建HttpContext实例。GetApplicationInstance使用HttpContext实例来确定针对这个请求该响应哪个虚拟路径,如果这个虚拟路径以前请求过,HttpApplication(或者一个继承于ASP.Global_asax的类的实例)将直接从应用程序池中返回,否则针对该虚拟路径将创建一个新的HttpApplication对象并返回。如下图所示:

HttpApplicationFactory.GetApplicationInstance带有一个类型为HttpContext的参数,创建的所有对象(产品)都是HttpApplication的类型,通过反编译,来看一下GetApplicationInstance的实现:

 1internal static IHttpHandler GetApplicationInstance(HttpContext context)
 2{
 3      if (HttpApplicationFactory._customApplication != null)
 4      {
 5            return HttpApplicationFactory._customApplication;
 6      }

 7      if (HttpDebugHandler.IsDebuggingRequest(context))
 8      {
 9            return new HttpDebugHandler();
10      }

11      if (!HttpApplicationFactory._theApplicationFactory._inited)
12      {
13            lock (HttpApplicationFactory._theApplicationFactory)
14            {
15                  if (!HttpApplicationFactory._theApplicationFactory._inited)
16                  {
17                        HttpApplicationFactory._theApplicationFactory.Init(context);
18                        HttpApplicationFactory._theApplicationFactory._inited = true;
19                  }

20            }

21      }

22      return HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);
23}

24

System.Web.IHttpHandlerFactory

我们来做进一步的探索,HttpApplication实例需要一个Handler对象来处理资源请求, HttpApplication的主要任务就是找到真正处理请求的类。HttpApplication首先确定了一个创建Handler对象的工厂,来看一下在Machine.config文件中的配置区<httphandlers>,在配置文件注册了应用程序的具体处理类。例如在Machine.config中对*.aspx的处理将映射到System.Web.UI.PageHandlerFactory 类,而对*.ashx的处理将映射到System.Web.UI.SimpleHandlerFactory 类,这两个类都是继承于IhttpHandlerFactory接口的具体类

<httpHandlers>

<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />

<add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory" />



</httpHandlers>

这个配置区建立了资源请求的类型和处理请求的类之间的一个映射集。如果一个.aspx页面发出了请求,将会调用System.Web.UI.PageHandlerFactory类,HttpApplication调用接口IHttpHandlerFactory中的工厂方法GetHandler来创建一个Handler对象。当一个名为sample.aspx的页面发出请求时,通过PageHandlerFactory将返回一个ASP.SamplePage_aspx对象(具体产品),如下图:

IHttpHandlerFactory工厂:

1public interface IHttpHandlerFactory
2{
3      // Methods
4      IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);
5      void ReleaseHandler(IHttpHandler handler);
6}

7

IHttpHandlerFactory.GetHandler是一个工厂方法模式的典型例子,在这个应用中,各个角色的设置如下:

抽象工厂角色:IHttpHandlerFactory

具体工厂角色:PageHandlerFactory

抽象产品角色:IHttpHandler

具体产品角色:ASP.SamplePage_aspx

进一步去理解

理解上面所说的之后,我们就可以去自定义工厂类来对特定的资源类型进行处理。第一步我们需要创建两个类去分别实现IHttpHandlerFactory IHttpHandler这两个接口。

 1public class HttpHandlerFactoryImpl:IHttpHandlerFactory {
 2   
 3   IHttpHandler IHttpHandlerFactory.GetHandler(
 4      HttpContext context, String requestType, 
 5      String url, String pathTranslated ) {
 6
 7         return new HttpHandlerImpl();
 8         
 9   }
//IHttpHandlerFactory.GetHandler
10
11   void IHttpHandlerFactory.ReleaseHandler(
12      IHttpHandler handler) /*no-op*/ }
13
14}
//HttpHandlerFactoryImpl
15
16public class HttpHandlerImpl:IHttpHandler {
17
18   void IHttpHandler.ProcessRequest(HttpContext context) {
19      
20      context.Response.Write("sample handler invoked");
21      
22   }
//ProcessRequest
23
24   bool IHttpHandler.IsReusable get return false; } }
25
26}
//HttpHandlerImpl
27

第二步需要在配置文件中建立资源请求类型和处理程序之间的映射。我们希望当请求的类型为*.sample时进入我们自定义的处理程序,如下:

<httpHandlers>

   
<add verb="*" path="*.sample" 

      type
="HttpHandlerFactoryImpl,SampleHandler" />

</httpHandlers>

最后一步我们需要把文件扩展*.sample映射到ASP.NET ISAPI扩展DLLaspnet_isapi.dll)上。由于我们已经建立了用于处理新扩展文件的处理程序了,我们还需要把这个扩展名告诉IIS并把它映射到ASP.NET。如果你不执行这个步骤而试图访问*.sample文件,IIS将简单地返回该文件而不是把它传递给ASP.NET运行时。其结果是该HTTP处理程序不会被调用。

运行Internet服务管理器,右键点击默认Web站点,选择属性,移动到主目录选项页,并点击配置按钮。应用程序配置对话框弹出来了。点击添加按钮并在可执行字段输入aspnet_isapi.dll文件路径,在扩展字段输入.sample。其它字段不用处理;该对话框如下所示:

.NET Framework中,关于工厂模式的使用有很多的例子,例如IEnumerableIEnumerator就是一个Creator和一个ProductSystem.Security.Cryptography中关于加密算法的选择,SymmetricAlgorithm, AsymmetricAlgorithm, HashAlgorithm分别是三个工厂,他们各有一个静态的工厂方法CreateSystem.Net.WebRequest .NET Framework 的用于访问 Internet 数据的请求/响应模型的抽象基类。使用该请求/响应模型的应用程序可以用协议不可知的方式从 Internet 请求数据。在这种方式下,应用程序处理 WebRequest 类的实例,而协议特定的子类则执行请求的具体细节。请求从应用程序发送到某个特定的 URI,如服务器上的 Web 页。URI 从一个为应用程序注册的 WebRequest 子代列表中确定要创建的适当子类。注册 WebRequest 子代通常是为了处理某个特定的协议(如 HTTP FTP),但是也可以注册它以处理对特定服务器或服务器上的路径的请求。有时间我会就.NET Framework中工厂模式的使用作一个专题总结。

实现要点

1.  Factory Method模式的两种情况:一是Creator类是一个抽象类且它不提供它所声明的工厂方法的实现;二是Creator是一个具体的类且它提供一个工厂方法的缺省实现。

2.  工厂方法是可以带参数的。

3.  工厂的作用并不仅仅只是创建一个对象,它还可以做对象的初始化,参数的设置等。

效果

1.  用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。

2.  Factory Method模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好的解决了这种紧耦合的关系。

适用性

在以下情况下,适用于工厂方法模式:

1.       当一个类不知道它所必须创建的对象的类的时候。

2.       当一个类希望由它的子类来指定它所创建的对象的时候。

3.       当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

总结

Factory Method模式是设计模式中应用最为广泛的模式,通过本文,相信读者已经对它有了一定的认识。然而我们要明确的是:在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。Factory Method要解决的就是对象的创建时机问题,它提供了一种扩展的策略,很好地符合了开放封闭原则。__________________________________________________________________________________

参考文献:

《设计模式》(中文版)

MSDN:《Exploring the Factory Design Pattern

DesignPatternsExplained

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2006-01-04 13:31 TerryLee 阅读(73036) 评论(169) 编辑 收藏

评论共2页: 上一页 1 2 
 回复 引用   
#68楼 2006-09-25 02:50 Spring[匿名][未注册用户]
谢谢TerryLee,是我的理解错误了,我想很多人提的这个问题可能都是和我的理解是一样的:以为用反射产生了这个如FileLog对象后,可能以后就不要在需要再产生FileLog类的另外一个对象了,所以就认为不要工厂类.前面的 领悟 所说的:
经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。

应用改成:
经常面临着“某类对象”的创建工作,由于需求的变化,这类对象的具体实现和数量经常面临着剧烈的变化,但是它却拥有比较稳定的接口。 这句话我想 领悟 也是这样理解的.我们抓住"某个"和"某类"这两个关键词来理解,你就不会再会产生如我所理解的那样了.

 回复 引用   
#69楼 2006-10-16 20:41 peacefulsword[未注册用户]
EventFactory类和FileFactory类好像编译不过,错误为Create()返回类型和父类不一致。
 回复 引用 查看   
#70楼[楼主] 2006-10-16 21:42 TerryLee      
@peacefulsword
示例代码有点问题,请看上面的评论!

 回复 引用   
#71楼 2006-10-31 17:26 kaixie[未注册用户]
@TerryLee
示例代码有点问题,就改过来吧,省得大伙再在这种问题上浪费时间了。

 回复 引用 查看   
#72楼[楼主] 2006-10-31 19:33 TerryLee      
@kaixie
呵呵,我也想改,老是顾不上啊,以前写得示例代码都不知道丢哪儿去了

 回复 引用   
#73楼 2006-11-11 21:17 roogeer[匿名][未注册用户]
想到什么就说什么了:

如果再结合原型模式呢?还需要抽象工厂吗?从反射中生成了一个对象,以后用时
clone()一下,代码中就不会有很多的那个什么(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);

是这样的吗?

 回复 引用 查看   
#74楼[楼主] 2006-11-12 17:08 TerryLee      
@roogeer[匿名]
解释累了,不想再在这上面纠缠下去了

结合原型模式,要创建一个对象,不也得一大堆代码吗?

 回复 引用   
#75楼 2006-11-17 11:22 来来去去[未注册用户]
@roogeer
不同的模式有不同的应用场景,要根据实际的需求来定模式,而不是用模式式去套需求

 回复 引用   
#76楼 2006-11-17 18:02 sz[未注册用户]
@sa
Assembly.Load("....").CreateInstance("NameSpace." + className);
这就是最漂亮的通用对象工厂呀。

其实Factory这个“轮子”已经发明了,为什么要刻意去造“轮子”?有如此好的语言特性为什么还揪着去创建自己的Factory呢?

 回复 引用   
#77楼 2006-11-29 09:14 Gary[匿名][未注册用户]
我刚从抽象工厂那边过来 感觉工厂模式与工厂方法基本是一样的
只是工厂方法只做一件事情
public abstract class LogFactory
{
public abstract void Write();
}
LogFactory可能需要多种实现:FileLog,EventLog,SqlLog...
但都是做“日志”
如果象你在抽象工厂里举的例子
public abstract class SalaryFactory
{
public abstract Bonus CreateBonus();
public abstract Salary CreateTax();
}
SalaryFactory需要计算奖金Bonus和个人所得税Tax
而Bonus和Tax都有不同的实现
其实质都是一样的
重要的是反射机制
(Factory)Assembly.Load(Path).CreateInstance(Path+factoryName);
可以根据与程序本身比较独立的配置文件决定相关工厂的具体实现。


至于用不用多次出现:
(Factory)Assembly.Load(Path).CreateInstance(Path+factoryName);
我想一旦:
Factory instanceA=(Factory)Assembly.Load(Path).CreateInstance(Path+factoryNameA);
instanceA内部的"方法"就是固定的了,只要instanceA内部的"属性"不变的话就可以把它当做一个"模子"来使用。
如果需要另外一种形状的模子那就不得不:
Factory instanceB=(Factory)Assembly.Load(Path).CreateInstance(Path+factoryNameB);
但是通常在一个运用中如果我只需要FileLog而不需要EventLog;
只需要按照中国的算法计算Bouns和Tax而不会考虑美国式的算法;

如果我需要FileLog也需要EventLog那就不应该在Log问题上使用工厂模式。

以上是我的感觉,请李大侠指正。
另外个人基础知识比较薄弱,对虚方法、接口的理解不够透彻,对虚方法在工厂模式里的使用感觉似懂非懂,肯请李大侠对虚方法、接口的功能和运用做一下总结。

 回复 引用   
#78楼 2007-02-05 10:13 moon[未注册用户]
TERRYLEE:
  首先感谢你的辛勤之作,写得也非常的好,有个小小的建议,不知可否,建议以后的配合源代码,这样能更好能验证

 回复 引用 查看   
#79楼[楼主] 2007-02-07 17:01 TerryLee      
@moon
谢谢,在以后的文章中我尽量注意这一点

 回复 引用 查看   
#80楼 2007-02-11 01:02 信元      
用工厂封装变化,在实例化的类有很多种构造函数的情况时更能体现它的优点。
不知道李哥是不是也遇到过这样的问题!
我前几天在对我的代码做重构的时候碰到过!

 回复 引用   
#81楼 2007-02-22 15:30 xiaozhi[未注册用户]
真的很好!
 回复 引用   
#82楼 2007-02-26 15:26 eleven[未注册用户]
1/**//// <summary>
2/// EventFactory类
3/// </summary>
4public class EventFactory
5{
6 public EventLog Create()
7 {
8 return new EventLog();
9 }
10}
11/**//// <summary>
12/// FileFactory类
13/// </summary>
14public class FileFactory
15{
16 public FileLog Create()
17 {
18 return new FileLog();
19 }
20}



是不是应该这样

1/**//// <summary>
2/// EventFactory类
3/// </summary>
4public class EventFactory
5{
6 public Log Create()
7 {
8 return new EventLog();
9 }
10}
11/**//// <summary>
12/// FileFactory类
13/// </summary>
14public class FileFactory
15{
16 public Log Create()
17 {
18 return new FileLog();
19 }
20}

 回复 引用   
#83楼 2007-03-07 14:29 XPP[未注册用户]
佩服作者,更佩服作者的回复,我学到了不少东西,谢谢你
 回复 引用   
#84楼 2007-03-13 20:56 andy[未注册用户]
樓主的解釋很好!其對人解釋相同的問題還是不厭其繁的解答,其修養更高。佩服!學到只是了!!
 回复 引用   
#85楼 2007-03-20 11:50 beyond[未注册用户]
谢谢楼主这么热心!文中的示例用Factory Method是不错的解决方案。不过我也试过和 @xxw 一样采用Singleton和反射来实现Log,以封装易变对象的变化部分,不知这样和Factory Method相比有什么问题。

Log类:
public abstract class Log
{
public abstract void Write();
}
具体实现:
public class FileLog:Log
{
public override void Write()
{
Console.Write("FileLog write ...");
}
}

public class EventLog:Log
{
public override void Write()
{
Console.Write("EventLog write ...");
}
}
生成Log对象:
public class CreateLog
{
private static Log _instance = null;

public static Log Instance()
{
if (_instance == null)
_instance = Create();

return _instance;
}

private static Log Create()
{
Log log;

string strLogName = ConfigurationSettings.AppSettings["LogName"];
log = (Log)Assembly.Load("Singleton").CreateInstance("Singleton." + strLogName);

return (log);
}
}
客户端:
class Client
{
static void Main(string[] args)
{
CreateLog.Instance().Write();

Console.Read();
}
}

 回复 引用 查看   
#86楼 2007-04-17 16:56 lingling      
看了你的抽象工厂和工厂方法都觉得很有感触,可是现在蒙了,觉不出这两者的差别呀,能否帮我解释一下,我是一个初学者,可能这个问题别人也问过甚至还有可能被问过很多遍了,可能你都不愿意说了,但是还是希望你能耐心的帮我讲讲,谢谢!
 回复 引用   
#87楼 2007-04-18 16:04 小菜[未注册用户]
14public class FileFactory:LogFactory
15{
16 public override FileLog Create()
17 {
18 return new FileLog();
19 }
20}
这个的public override FileLog Create()
返回值是否该是Log呢,按上面写法VS编译报错呦:(
public abstract class LogFactory//这个里面的抽象方法返回的是Log啊
5{
6 public abstract Log Create();
7}

 回复 引用   
#88楼 2007-04-26 15:49 pzq[未注册用户]
想想看,如果没有反射,工厂是不是能保证最少修改的方法呢?

注意一个前提,设计模式这种东西,尤其是GOF23,都是源自C++时代的产物,对于最新的语言技术而言,已经有些过时了。

 回复 引用   
#89楼 2007-05-30 10:17 ben[未注册用户]
好文章。
其实工厂模式说白了就是:申明了一个父类的类变量确实例了该父类的子类!
不知道这样理解是否正确!呵呵

 回复 引用   
#90楼 2007-06-13 17:10 qingyun163[未注册用户]
我也有大家的疑问,我感觉不要工厂类就可以,至于你说的这个问题:

string strlogName=System.Configuration.ConfigurationSettings.AppSettings["logName"];
Log log; log=(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);
--------
想想这样程序中充斥着大量的这样的代码,你觉不觉会有问题呢?

---------
我们可以把这个封装到一个方法中去,其他地方调用就可以了。在这个例子中,一个工厂类对应创建一个产品,没有任何逻辑,这和直接创建几乎没有区别。我觉得工厂类一定有一些逻辑,否则就没有使用工厂类的意义了。楼主是不是可以再举一个例子呢?

 回复 引用   
#91楼 2007-06-19 10:10 NULL[未注册用户]
看过几篇工厂方法的文章,就你这篇看的最清楚。
看来,你不是牛A也不是牛C啊。

 回复 引用   
#92楼 2007-06-29 16:53 yoyolion
认真看了博主的贴子和回复,感触很深

首先非常感谢博主写出这么好的文章。候捷说过人最缺乏的是有一个类似源代码的版本管理器类的机制,领悟和掌握了之后就很可能忘记了当时学习时的举步维艰和顿悟时的喜悦,更难得是能将这些经历分享。博主花了大量的时间和心血在分享、传播对设计模式的理解上,非常值得敬佩。

再看前面的回复,这样精彩的文章确实引发了热烈的反应和讨论。作者不厌其烦的进行回复和解释,更值得敬佩。

再次感谢博主。

最后回到文章的内容上来,我觉得上面beyond的代码非常好的解决这个文章提出问题的需要,充分利用了反射特性,更减少了对象的实例化次数。

pzq说的很精彩
“如果没有反射,工厂是不是能保证最少修改的方法呢”
sz网友的“Assembly.Load("....").CreateInstance("NameSpace." + className);
这就是最漂亮的通用对象工厂呀。 ”

在反射机制的支持下,确实已经就实现了保持对修改封闭。结合单件模式的运用,更减少了系统开销。这样的解决方案我认为比博主的工厂模式更实用。

是否工厂模式还有其更适用的场合?


 回复 引用   
#93楼 2007-07-17 03:11 yanzimywife[未注册用户]
Terrylee 我认为工厂方法要当作Template Method模式的一种特殊形式来理解的.而不能当做一个工厂类来理解,不知道我这样想是对的么??

 回复 引用 查看   
#94楼 2007-07-27 22:57 Leepy      
这篇文章没有实例么?
 回复 引用 查看   
#95楼 2007-08-19 18:48 Gavin.W.Lai(赖文华)      
作者不厌其烦的进行回复和解释,值得敬佩。
学习....

 回复 引用   
#96楼 2007-09-10 12:14 华为菜鸟[未注册用户]
来的次数多了,很多东西自然就会有点自己的看法了!
 回复 引用   
#97楼 2007-09-13 15:11 日语[未注册用户]
郭先生
地址:北京海淀区太阳园17号楼405室  邮编:100098

 回复 引用   
#98楼 2007-09-13 15:13 翻译人才网[未注册用户]
hen hao
 回复 引用   
#99楼 2007-09-13 15:13 在线翻译[未注册用户]
OK
 回复 引用   
#100楼 2007-09-26 13:12 过路人[未注册用户]
Log的例子已经是抽象工厂了吧
 回复 引用 查看   
#101楼 2007-10-15 20:04 荒芜      
6 public static void Main(string[] args)
7 {
8 LogFactory factory = new EventFactory();
9
10 Log log = factory.Create();
11
12 log.Write();
13 }

6 public static void Main(string[] args)
7 {
8 Log factory = new EventLog();
9

11
12 factory.Write();
13 }
这个的优点体现在哪里??
请原谅我的无知!!
还有请教.工厂方法模式需要产品对应一个Factory,是不是意思就是工厂方法模式比较适合产品比较少的环境下.当一个Factory如果有很多产品的话,是不是用简单工厂模式或者抽象工厂模式比较适合?

 回复 引用 查看   
#102楼 2007-10-20 09:08 flyingfish      
写的很好,支持。总结一下核心含义:
工厂方法解决单个异变对象,就是消灭Case语句对扩展的限制。
将创建时机延迟问题。
工厂和产品同样的层次结构。
使用反射机制配置选择具体工厂类。

 回复 引用 查看   
#103楼 2007-10-20 09:21 flyingfish      
@荒芜
你写的两种方式中,第一种比起第二种的好处在于包装了产品的创建。因为具体产品的创建可能不是一个new就能完成的。这种包装也是个进步。

但是你写的两种方式都不是工厂方法最终要呈现的,一般现实中都会用从更外层调用传入工厂类或者用反射之类的东西。以避免增加产品后所有用到产品类的DLL从新编译和部署。

工厂方法模式应该和产品种类个数无关。

 回复 引用   
#104楼 2007-11-15 19:25 雪融蓝海[未注册用户]
你好,我是C#的初学者,请问可否可我发一份工厂模式的源代码,好吗,谢谢!
 回复 引用   
#105楼 2007-11-21 11:53 收藏人[未注册用户]
希望多写点初学者应该学习的东西,虽然我还是一知半解。但写的还是蛮有思路的,学习了!
 回复 引用   
#106楼 2008-01-09 17:13 PeterChen[未注册用户]
TerryLee你的文章写的太好了,还有你耐心的解释。我在这里向你请求一份该例子的代码.
我的EMAIL是:PeterChenSun@hotmail.com

 回复 引用 查看   
#107楼[楼主] 2008-01-09 18:29 TerryLee      
@PeterChen
抱歉,这篇文章已经是2年前的了,示例代码找不到了:)

 回复 引用 查看   
#108楼 2008-01-10 13:13 hq2008      
"它调用了一个静态的工厂方法HttpApplicationFactory.GetApplicationInstance,通过它来创建HttpContext实例。"是这样子吗?
 回复 引用 查看   
#109楼 2008-02-17 21:46 ♂风车车.Net      
感谢大哥你的好文章!
报告,我转载了你的文章到我的blogs!
http://www.cnblogs.com/xray2005/archive/2008/02/17/1071576.html

 回复 引用 查看   
#110楼[楼主] 2008-02-21 19:13 TerryLee      
@♂风车车.Net
随便转载,呵呵,只要保留原文出处就行了:)

 回复 引用 查看   
#111楼 2008-03-16 12:04 狼Robot      
学习了.
 回复 引用 查看   
#112楼 2008-03-16 12:18 狼Robot      
如果这里的抽象log改成接口log不知道有没有什么问题?
 回复 引用 查看   
#113楼 2008-03-16 12:50 狼Robot      
我始终对接口和抽象的使用场合搞不清,不知道楼主有没有相关的文章推荐?
 回复 引用 查看   
#114楼[楼主] 2008-03-16 16:12 TerryLee      
@狼Robot
没有问题,如果你想在父类中有部分实现的话,需要用抽象类,否则只是简单的契约声明,就可以用接口了。

这方面的文章网上有一大堆啊,搜索一下,应该可以找到的

 回复 引用   
#115楼 2008-03-30 16:16 Doo[未注册用户]
跟着前人的脚印,一步步走来.在这里找到
.net 设计模式.
看了看文章的发表日期,已经是2年前的了
强文呀~~就算是费话,也要回一贴

 回复 引用 查看   
#116楼 2008-04-03 08:58 菜鸟毛      
李老师,似乎前面的客户端调用可以写为factory.Create().Write();啊,为何要以Log去调用呢.
 回复 引用 查看   
#117楼 2008-04-03 10:08 菜鸟毛      
而且,似乎Log的方法一旦增加,是否LogFactory的方法也要随之增加呢...这样做改动似乎不是更小了,而是更大了.
 回复 引用 查看   
#118楼 2008-05-15 11:48 kkun      
为什么会报错呢?说返回类型不一样,不能重写,能帮我看看吗
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Tstring.Comm {

#region

public abstract class CommBase { }

public class UserInfo : CommBase { }

public class EnentInfo : CommBase { }

#endregion

#region
public abstract class CommFactory {
public abstract CommBase Create();
}

public class UserInfoFactory : CommFactory {
public override UserInfo Create() {//这里报错...
throw new NotImplementedException();
}
}
#endregion

#region
public class Test {
void Main() {
}
}
#endregion
}

 回复 引用 查看   
#119楼 2008-06-02 00:28 osman-jiang      
想想这样程序中充斥着大量的这样的代码,你觉不觉会有问题呢?
--------------------------------------------
string strlogName=System.Configuration.ConfigurationSettings.AppSettings["logName"];
Log log; log=(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);

------------------------------------------------
这段代码封装到一个方法中,每次只用调用这个方法即可。

我刚刚用工厂方法写了一个小demo,写完之后才发现完全没必要用。上面也有很多人有这个疑问。我觉得 这段代码封装到一个方法中,每次只用调用这个方法即可。

另外从 EventLoglog = new EventLog(); 到 Log log = new EventLog();到 Log log = new factory.creat(); 是从全部的具体类,到全部的接口。
但不管怎么样。一个对象不反射出来就要new出来。只不过是换了个地方new而已。而先new一个工厂然后由工厂create一个log。似乎没有体现工厂方法的作用。我想在存在反射技术的情况下,工厂方法都没什么必要了。

 回复 引用 查看   
#120楼 2008-06-25 02:18 水言木      
不知道是不是太困了看傻了,这次(第二次看到这篇文章)看时竟然有点不理解了:
EventLog eventlog = new EventLog();
eventlog.Write();

这里通过基类来调用:
Log log = new EventLog();
log.Write();

这样的话和:
LogFactory factory = new EventFactory();
Log log = factory.Create();
log.Write();

相比会差很多?感觉其实是一样的啊

请指点...

 回复 引用 查看   
#121楼 2008-07-06 19:27 水言木      
@水言木
自己已经想通了,呵呵

 回复 引用 查看   
#122楼 2008-07-10 12:08 gotolovo      
--引用--------------------------------------------------
水言木: 不知道是不是太困了看傻了,
这次(第二次看到这篇文章)
看时竟然有点不理解了:
EventLog eventlog = new EventLog();
eventlog.Write();
这里通过基类来调用:
Log log = new EventLog();
log.Write();
这样的话和:
LogFactory factory = new EventFactory();
Log log = factory.Create(); log.Write();
相比会差很多?感觉其实是一样的啊
请指点...
--------------------------------------------------------
困惑一段时间了 还请指教啊

 回复 引用 查看   
#123楼 2008-09-17 14:14 贝贝(zbc)      
有很多人水平比我高,偶尔也有初学者的问题无人回答.
总结一下就是这样:
如果你想代码简洁,就很难避免强耦合,修改非常不方便.而真正面向对象的出发点就是降低耦合.
硬要说效率的话,对于一个固定的小程序来说,不考虑到修改,用IF,CASE更有效率.而且程序跑起来也更快.
所有能用IF,case解决的问题都能用多态,继承来改写,问题是这样值不值得.最关键的地方是看扩展和修改到底方不方便.
设计模式的目的还有一个就是提高复用和不改变已有代码.而IF,CASE这种结构在扩展时是完全避免不了修改的.

我对FRAM2.0里的工厂模式的应用比较感兴趣,希望楼主能早日总结成文,让我等学习.

 回复 引用 查看   
#124楼[楼主] 2008-10-08 11:17 TerryLee      
@水言木
@gotolovo
感觉怎么会一样呢,现在已经脱离了对EventLog的依赖,注意,EventLog在这个示例中属于容易变化的部分,我们要做的是尽量依赖于稳定不变的部分。

 回复 引用 查看   
#125楼 2008-10-17 12:24 东风梦遥      
冒昧请教个问题 楼主强调过这样一个问题:

###################################
@领悟
呵呵,不用试也知道是对的

可是你又忽略了一个问题,那就是这个系统中变化较多的是哪些?哪些变化是相对较慢的?如果每需要一个Log对象,你都得用以下这样一段代码:
--------
string strlogName=System.Configuration.ConfigurationSettings.AppSettings["logName"];
Log log; log=(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);
--------
想想这样程序中充斥着大量的这样的代码,你觉不觉会有问题呢?但是如果用工厂呢?还有建议看看上面的评论等,其实我已经解释过很多次这个问题了:)
########################################

但是你的
################################
1/**//// <summary>
2/// App类
3/// </summary>
4public class App
5{
6 public static void Main(string[] args)
7 {
8 string strfactoryName = ConfigurationSettings.AppSettings["factoryName"];
9
10 LogFactory factory;
11 factory = (LogFactory)Assembly.Load("FactoryMethod").CreateInstance("FactoryMethod." + strfactoryName);
12
13 Log log = factory.Create();
14 log.Write();
15 }
16}
###############################

你的这样的代码
string strfactoryName = ConfigurationSettings.AppSettings["factoryName"];
9
10 LogFactory factory;
11 factory = (LogFactory)Assembly.Load("FactoryMethod").CreateInstance("FactoryMethod." + strfactoryName);
12

不也是需要大量存在吗?请赐教,你也并没有封装LogFactory 的创建过程呀

 回复 引用 查看   
#126楼[楼主] 2008-10-24 10:18 TerryLee      
@东风梦遥 存在这样大量的代码,但是你注意到没有,这些代码中并没有与具体的Logger相关的任何信息。要解决这个问题,就不是Factory Method模式的问题了,你可以使用其它的方式做一个简单的封装,如使用外观模式等。
 回复 引用 查看   
#127楼 2008-10-29 10:28 Zero.Li      
@东风梦遥的问题很有意思,楼主的代码的确没有Logger的相关信息,因为它们都被封装到factory的套套里面去了,又因为factory的Create()定义为实例化对应的log对象,调用Create()就等于调用了它对应logo的具体信息了啊.

我个人的理解工厂是用于生产产品的,而每种产品都有其用途, 比方说现在有EventLog 和 FileLog, 使用的时候我可能不止通过单一的配置文件来选择EventLog的生产线或者FileLog的生产线, 而是灵活的得到我想要的产品,可能是EventLog,可能是Filelog,也可能两者同时.(感觉又有些像builder模式了..)

 回复 引用 查看   
#128楼 2008-11-21 10:35 neil-zhao      
楼主您好!
我认认真真的看了您的
工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)
两篇文章,我怎么感觉您的两个实例解决的是同一个问题啊。是不是这两个模式是一样的啊!!
能不能给哥们解释一下啊。非常感谢

 回复 引用 查看   
#129楼[楼主] 2008-11-21 12:22 TerryLee      
@neil-zhao
我在这里解释过了:
http://space.cnblogs.com/question/2455/

 回复 引用 查看   
#130楼 2008-12-03 09:29 伟雄      
好文,继续研究
 回复 引用 查看   
#131楼[楼主] 2008-12-08 10:52 TerryLee      
@伟雄
:)

 回复 引用 查看   
#132楼 2008-12-31 11:16 Fengdesudu      
好文,准备再继续读下去
 回复 引用 查看   
#133楼 2009-01-01 23:59 pillow      
工厂方法是解决new的问题.也就是拷贝的问题.享元是利用拷贝.原型是灵活运用浅拷贝和深拷贝的问题.反正我觉得拷贝,浅拷贝,深拷贝的作用和意义在设计模式当中凸显了出来.
拷贝:对象之间的Reference是一样的.指针不同,内容完全相同,内存中就是一份.
浅拷贝:对象之间的值在内存中有两份,但是引用类型在内存中是共享一份.
深拷贝:值和引用类型在内存中都有两份.

 回复 引用 查看   
#134楼 2009-01-02 10:57 会长      
@Terrylee

“@水言木
@gotolovo
感觉怎么会一样呢,现在已经脱离了对EventLog的依赖,注意,EventLog在这个示例中属于容易变化的部分,我们要做的是尽量依赖于稳定不变的部分。”

还是不太明白,呵呵,虽然EventLog容易变化,可是其接口是稳定的,似乎
Log log = new EventLog(); 也是可行的。
工厂模式最大的好处是不是去掉了这个“new”。因为不是实例化一个具体的实例从而起到了EventLog和客户代码之间的松耦合,但是这样也要new一个对应的工厂类,糊涂了,请楼主指教一二,呵呵。

 回复 引用 查看   
#135楼[楼主] 2009-01-04 11:10 TerryLee      
@Fengdesudu
谢谢支持:)

 回复 引用 查看   
#136楼[楼主] 2009-01-04 11:11 TerryLee      
@pillow
工厂模式跟这两个区别挺大的。

 回复 引用 查看   
#137楼[楼主] 2009-01-04 11:13 TerryLee      
@会长
Log log = new EventLog(); 也是可行的。
————————————————————————
这个依赖于EventLog,我已经说过了,设计模式是寻找变化点,然后进行封装,这个例子中EventLog属于具体的实现,它是易变化的部分,所以需要对它封装,Log log = new EventLog(); 这样写明显与EventLog发生了强的依赖。至于对应的工厂类,完全可以通过别的手段来解决。

 回复 引用 查看   
#138楼 2009-01-04 13:06 会长      
@TerryLee
感谢楼主的解答,待我再学习学习,回过头来再拜读楼主的文章也许就会有不一样的收获。新年快乐

 回复 引用 查看   
#139楼[楼主] 2009-01-05 01:23 TerryLee      
@会长
同乐,呵呵:)

 回复 引用 查看   
#140楼 2009-01-06 22:08 pillow      
设计模式关键是把握变化点。特别是初学很容易设计过渡。可以根据实际的情况。或减少一些抽象,或增加一些抽象。比如这里面的抽象工厂类根据不同情况可有可无。因为既然用了new那么左边用接口和抽象类,右边用子类是没有大多意义的。用抽象是解藕。如果没有做到就没有必要抽象。不知道对么?高手指教!
 回复 引用 查看   
#141楼 2009-01-07 16:05 pillow      
工厂模式用的还是比较多的。因为本来就是面向对象的,对象的创建无处不在阿。所以工厂用的比较多。
 回复 引用 查看   
#142楼[楼主] 2009-01-12 11:34 TerryLee      
@pillow
设计模式的关键是封装变化点,一般来说,抽象的东西是相对稳定的,而具体实现的东西是容易变化的,所以要依赖于抽象。

 回复 引用 查看   
#143楼 2009-02-09 15:44 杨艳平      
@TerryLee
楼主的工厂模式写的通俗易懂!我看了搂主的日志记录的例子,改写了下,请搂主指点下不足的地方:
using System;

namespace DMedia.NongXinTongService.log4net
{
/// <summary>
/// 日志记录接口
/// </summary>
public interface ILog
{
void Write();

void Write(string log);
}
}

using System;

namespace DMedia.NongXinTongService.log4net
{
/// <summary>
/// EventLog类
/// </summary>
internal class EventLog:ILog
{

#region ILog 成员

public void Write()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}

public void Write(string log)
{
throw new NotImplementedException();
}

#endregion
}
}

using System;

namespace DMedia.NongXinTongService.log4net
{
/// <summary>
/// FileLog类
/// </summary>
internal class FileLog:ILog
{

#region ILog 成员

public void Write()
{
throw new NotImplementedException();
}

public void Write(string log)
{
throw new NotImplementedException();
}

#endregion
}
}

using System;

/*
* 功能:工厂模式(日志)
* 日期:2009-2-7
*/

namespace DMedia.NongXinTongService.log4net
{
interface ILogFactory
{
ILog Create();
}
}

using System;

namespace DMedia.NongXinTongService.log4net
{
/// <summary>
/// EventLogFactory类
/// </summary>
internal class EventLogFactory:ILogFactory
{
#region ILogFactory 成员

public ILog Create()
{
return new EventLog();
}

#endregion
}
}

using System;

namespace DMedia.NongXinTongService.log4net
{
/// <summary>
/// FileLogFactory类
/// </summary>
internal class FileLogFactory:ILogFactory
{
#region ILogFactory 成员

public ILog Create()
{
return new FileLog();
}

#endregion
}
}

using System;
using System.Reflection;
using System.Configuration;

namespace DMedia.NongXinTongService.log4net
{
/// <summary>
/// 日志入口类
/// </summary>
public class LogManager
{
private static readonly string path =ConfigurationSettings.AppSettings["LogPath"];
private static readonly string className = ConfigurationSettings.AppSettings["LogClassName"];

private static ILog _log;

public static ILog CreateLog()
{
if (_log == null)
{
ILogFactory logFactory = (ILogFactory)Assembly.Load(path).CreateInstance(className);
_log = logFactory.Create();
}
return _log;
}
}
}
请搂主看看那里有不足的地方

 回复 引用 查看   
#144楼 2009-03-04 13:41 李松-2008      
dddddd起
 回复 引用 查看   
#145楼 2009-03-18 10:29 重庆串串      
看了几遍,终于领会了工厂模式的魅力。谢谢老李,继续拜读您的文章
 回复 引用   
#146楼 2009-04-25 11:34 sstgjbj
你们学了那么久了,看来我拉后了,加油
 回复 引用   
#147楼 2009-04-29 11:35 stones
向你表达敬意
 回复 引用   
#148楼 2009-05-04 13:43 stones
关于楼主的下面回复有些不明白,还希望楼主指点下!!!

“@水言木
@gotolovo
感觉怎么会一样呢,现在已经脱离了对EventLog的依赖,注意,EventLog在这个示例中属于容易变化的部分,我们要做的是尽量依赖于稳定不变的部分。”

如果使用工厂模式,每添加一个LOG子类,就要添加一个新的LogFactory派生类,LOG属于易变化的类,但LogFactory也属于易变化的类,虽然脱离了对LOG的依赖,但对于LogFactory有了依赖,这样“我们要做的是尽量依赖于稳定不变的部分”不就不成立了吗?
刚开始学,请楼主指点了!!

 回复 引用   
#149楼 2009-06-04 17:10 虚心菜鸟
看了李老师的http://space.cnblogs.com/question/2455/解释,还是有点不明白,按李老师的说法是不是可以这样理解:在抽象工厂类派生的每个具体工厂类中创建一个具体产品实例的模式是工厂方法模式,而创建多个具体产品实例的模式就是抽象工厂模式。如果仅有此区别,那分为两种模式又有什么意义呢?还有“每个抽象产品派生多个具体产品类”这句话什么意思,在本片博文中抽象产品及具体产品类各指哪些类呢?谢谢
 回复 引用   
#150楼 2009-06-04 17:20 虚心菜鸟
另外还有一个问题,希望李老师给指点指点:
那就是关于.net学习的问题。我现在学习.net一段时间了,学习了HTML、CSS、C#语法、WEB DEVELEPOR平台、AJAX及JAVASCRIPT等基础知识,如果我想在B/S企业级项目开发方面有所发展的话,我应该接下来再学习哪些知识呢,望楼主指点,不胜感激!

 回复 引用   
#151楼 2009-07-23 12:53 狗剩2[未注册用户]
已经是第三,(或四)次到这TERRY,的这篇BLOG上来了,这次用一上午的时间学习了一下(工作置后),上面介绍工厂方法的示例,已经可以在仔细看一遍后,凭回忆写出了,我知道这个还不够,很多东西还是要了解,下一步是在今天下午学习抽象工厂,
ASP.NET HTTP通道中的应用,这段内容没有耐心看了,估计再过半年会学习后半部分的,

 回复 引用 查看   
#152楼 2009-08-04 14:22 小多      
LogFactory factory;
factory = (LogFactory)Assembly.Load("FactoryMethod").CreateInstance("FactoryMethod." + strfactoryName);
请问一下,这个就是所谓的反射吗?
使用这种方法的优点在哪?

 回复 引用 查看   
#153楼 2009-08-06 10:04 孤苏一叶      
public class EventFactory :LogFactory
{
public override EventLog Create()
{
return new EventLog();
}
}
我按照楼主的代码去运行,提示以下错误

EventFactory.Create(): 返回类型必须是“Log”才能与重写成员LogFactory.Create

我是新手,请多多指教

 回复 引用 查看   
#154楼 2009-10-23 16:12 Mr雨      
直接用简单工厂
声明Log 用反射实例化 在配置文件配置EventLog,FileLog等,
是不是更好呢~~

 回复 引用 查看   
#155楼 2009-10-23 18:23 差一点      
被抽象工厂和工厂方法搞晕了。
 回复 引用 查看   
#156楼 2009-12-01 18:14 臭脚大仙      
工厂与抽象工厂的区别:
工厂模式中,创建产品被延迟到子工厂中去实现。
抽象工厂模式中,由抽象工厂直接创建出产品。
工厂模式中,产品与子工厂是一对一的关系,就是一个产品,必然由某一子工厂来生产。
抽象工厂模式中,抽象工厂与产品是一对多的关系,即,一个抽象工厂可以生产出许多种产品,即产品的生产是在抽象工厂里进行的,而并不像工厂模式那样,延迟到子工厂去。
------------------------------------------------------
俺是才开始学习这个的,欢迎大家来扔砖头。

 回复 引用 查看   
#157楼 2010-02-11 15:24 binjuny      
你好,对于工厂方法我一直有一个疑惑,就是对于每个产品都会有一个工厂类,如果有很多的产品类,那会不会造成类的膨胀啊?期望你的解答。谢谢
 回复 引用 查看   
#158楼 2010-10-12 11:32 YoungSin      
引用臭脚大仙:
工厂与抽象工厂的区别:
工厂模式中,创建产品被延迟到子工厂中去实现。
抽象工厂模式中,由抽象工厂直接创建出产品。
工厂模式中,产品与子工厂是一对一的关系,就是一个产品,必然由某一子工厂来生产。
抽象工厂模式中,抽象工厂与产品是一对多的关系,即,一个抽象工厂可以生产出许多种产品,即产品的生产是在抽象工厂里进行的,而并不像工厂模式那样,延迟到子工厂去。
------------------------------------------------------
俺是才开始学习这个的,欢迎大家来扔砖头。



虚拟工厂后面创建产品时中间可以再挂入工厂模式,这样可能是比较好的一种形式

 回复 引用 查看   
#159楼 2010-10-29 10:18 南雁北飞      
看完了所有的评论,才发现自己理解的和大多数人理解的是一样的,而且楼主一直也没有给出合理的解释。Log是易变化点没错,如果增加一个Log,就必须增加一个Factory,传递性的带动了Factory的变化,这样的工厂方法不仅没有解决根本的问题,还做问题更复杂化了。
 回复 引用 查看   
#160楼 2010-11-25 10:36 WCF技术联盟      
GOF中说,抽象工厂跟工厂方法一个很重要的区别是,
抽象工厂是采用组合的思想,而工厂方法是继承的思想,
我看了您的两篇文章,您只体现了他们在一个产品跟一系列产品创建上的区别,但并没有体现出他们在继承还是组合这一点上的区别,
您的文章给我的感觉似乎是,抽象工厂跟工厂方法都是运用继承的思想。

 回复 引用 查看   
#161楼 2011-01-21 14:43 sendiar      
引用TerryLee:
<br>呵呵,我也想改,老是顾不上啊,以前写得示例代码都不知道丢哪儿去了

你好,怎么我找不到示例代码下载的?
在哪下载的??

 回复 引用 查看   
#162楼 2011-01-21 14:45 sendiar      
示例代码是不是没得下载了??
 回复 引用 查看   
#163楼 2011-05-12 10:25 TSAPI      
public override EventLog Create()
7 {
8 return new EventLog();
9 }
这里的EventLog 应该是log才对,然后返回的是EventLog;谢谢

 回复 引用 查看   
#164楼 2011-06-14 15:10 Daywei      
引用TSAPI:
public override EventLog Create()
7 {
8 return new EventLog();
9 }
这里的EventLog 应该是log才对,然后返回的是EventLog;谢谢

大哥 好好看看评论好吧,大家已经在评论中说了这里要改了,只不过lz没有修改原文,我觉得这样也挺好,从怀疑到大家一步步讨论到得出一致的结论的这种方式挺好。

 回复 引用 查看   
#165楼 2011-06-14 15:12 Daywei      
我还有一种自己的理解方式,因为我是学数学的,我是这样理解的
这种区别 我可以这样理解吗?抽象工厂是解决多维的问题,而工厂模式只是解决单维的问题??还请前辈赐教!

 回复 引用 查看   
#166楼 2011-08-18 12:50 叶鹏      
怎么到现在作者不把示例代码的错误更正过来,难道是加强映像?
 回复 引用 查看   
#167楼 2011-10-26 19:52 花未全开      
public abstract class LogFactory
5{
6 public abstract Log Create();
7}
8
此时两个具体工厂的代码应该如下:
1/// <summary>
2/// EventFactory类
3/// </summary>
4public class EventFactory:LogFactory
5{
6 public override EventLog Create()
7 {
8 return new EventLog();
9 }
10} 这样也能重写???

评论共2页: 上一页 1 2