.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 阅读(39371) 评论(152)  编辑 收藏 网摘 所属分类: [05]  架构与设计

  回复  引用    
#1楼 2006-01-06 16:31 | 180 [未注册用户]
看了这么多篇讲工厂模式的文章,就数这篇的例子讲解最清晰,对工厂模式的原则阐述最直接。谢谢!
  回复  引用  查看    
#2楼 [楼主]2006-01-06 16:52 | Terrylee      
@180

呵呵,过奖了~

探索设计模式系列的随笔我会继续努力写好的

  回复  引用    
#3楼 2006-01-07 14:03 | Benjamin [未注册用户]
很好。。。。。。

简介明了的诠释了 工厂模式

  回复  引用  查看    
#4楼 2006-01-08 00:18 | 天涯海角      
好文章,收藏.
  回复  引用  查看    
#5楼 2006-01-11 13:01 | 领悟      
非常感谢。讲得很好。
很清析。

  回复  引用  查看    
#6楼 2006-01-20 10:08 | 曾哲      
非常好,希望多出
  回复  引用  查看    
#7楼 [楼主]2006-01-20 11:31 | Terrylee      
春节过后,我会继续写完结构型设计模式和行为型设计模式的文章:)
  回复  引用  查看    
#8楼 2006-02-17 10:24 | 半梦半醒之间      
我是在期刊上面看到的你的文章,觉得很有启发,以前也看过类似的文章,感觉概述的部分有点勉强。

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

如果是上面的场景,我想只要在程序中调用接口固定的父类就可以了,多数情况是没必要使用工厂模式的。

概述部分的思路不错,产品的共性有很多种,不一定只是车、马形式,也可以是新、旧形式,只要有共性就好。

  回复  引用  查看    
#9楼 [楼主]2006-02-17 13:50 | Terrylee      
@半梦半醒之间
非常感谢你提出的意见,但是我个人认为
不管怎么调用接口,总是不能避免如下语句的使用:
ILog log = new EventLog();
如果调用父类接口就可以实现功能的话,具体类的存在没有意义了。

  回复  引用  查看    
#10楼 2006-02-17 14:10 | 半梦半醒之间      
我看不出你的模式使用中有什么错误,只是觉得很多场合下,不使用模式更简单,客户是不是需要我们那么灵活呢?多数都不需要。这篇文章给我最大的提示是产品的共性,我举一反三的能力比较差,以前很少想这么多,所以才回了几句。

以上是个人观点,我对模式方面也很感兴趣,但是一直没有深入研究这些东西,因为我总想找一些模式应用的具体信息来学习,还找不到。

感觉模式是学不会的,仅仅可以帮助我们总结自己的经验,给我们自己的总结提供个思路。用了模式之后才明白什么是模式,这时候已经会了。

  回复  引用  查看    
#11楼 [楼主]2006-02-17 14:52 | Terrylee      
@半梦半醒之间
你说的对,模式并不是任何时候都可以用,只是用在我们需要的地方,否则就是对模式的一种误用,因为模式本身是为了提高程序的可扩展性和可维护性的,而并不能提高程序的性能,所以使用模式还是应该慎重。

学习设计模式,更加能提高我们的抽象能力。我也是刚开始学习设计模式,想借助写这样一系列文章来加深自己对设计模式的认识,不知何时才能写完,呵呵。写每一个模式的时候用什么样的例子去说明,就得想好长时间……

  回复  引用    
#12楼 2006-03-02 15:41 | SEANYANG [未注册用户]
牛人啊,真的還厲害!
  回复  引用    
#13楼 2006-03-21 13:47 | Lucifinil [未注册用户]
您好,我是初学者.
能讲讲 Abstract Factory 和 Factory Method的区别吗?

  回复  引用  查看    
#14楼 [楼主]2006-03-23 08:24 | Terrylee      
@Lucifinil
抽象工厂解决的问题是一个系列的对象的创建,而工厂方法解决的是某个对象的创建。

单个汽车对象的创建,单个对象

各种颜色风格的汽车对象的创建,一系列对象

有点理论化了,有时间我会写一篇文章来说明一下:)

  回复  引用    
#15楼 2006-03-24 13:09 | lw [未注册用户]
你好
我现在也在研究设计模式你上面写的文章很好
我很想知道以你现在这样的水平工资能那多少啊

  回复  引用  查看    
#16楼 [楼主]2006-03-24 13:18 | Terrylee      
@lw
呵呵~~~~

这个问题好像不适合在这儿讲吧?

  回复  引用  查看    
#17楼 2006-03-28 14:27 | 蓝鸟      
我是模式的初学者,以前看了许多关于模式的讲解,看到这篇后突然有了醍醐灌顶的感觉,谢谢,希望你能写出更好的文章来
  回复  引用  查看    
#18楼 [楼主]2006-03-28 15:11 | Terrylee      
@蓝鸟
谢谢:)

这个系列的文章我会介绍介绍完GOF23中经典模式之后,再做一些案例的综合分析等等~~~,我争取在后续文章中写得更好!

  回复  引用    
#19楼 2006-04-26 17:12 | Mutou [未注册用户]
从这章起是不是就没有源代码下载了。其实我很需要它的,谢谢
  回复  引用  查看    
#20楼 [楼主]2006-04-26 17:32 | Terrylee      
@Mutou

后来我写的重在于分析整个的过程,如果您需要相关的源程序的话,可以发Email给我,我发给你!

  回复  引用  查看    
#21楼 2006-05-05 18:02 | 叫我燕哥      
为什么用继承不用接口(interface)呢?

public abstract class Log
{
public abstract void Write();
}

public class EventLog:Log
{
public override void Write()
{
Console.WriteLine("EventLog Write Success!");
}
}

public class FileLog:Log
{
public override void Write()
{
Console.WriteLine("FileLog Write Success!");
}
}

这里用Interface效果应该更好,然后创建一个工厂类,工厂类里放入接口对象,通过用户不同的需求,将接口对象实力化为不同的类,如:
接口:
public interface Log()
{
void Write(string logContent);
}
具体类:
public class EventLog:Log
{
public void Write(string logContent)
{
Console.WriteLine("EventLog Write Success!");
}
}
public class FileLog:Log
{
public void Write(string logContent)
{
Console.WriteLine("FileLog Write Success!");
}
}
工厂类:
public class LogOperate
{
//定义接口对象
Log log;

public enum LogType{File,Event};
public LogType logType;

//获取用户需要的对象
public Log GetLog()
{
switch(logType)
{
case LogType.Event:
log = new EventLog();
break;
case LogType.File:
log = new FileLog();
break;
}
return log;
}
}
外部调用:
LogOperate logOperate = new LogOperate();
logOperate.logType= LogOperate.LogType.File;
Log log = logOperate.GetLog();
log.Write("日志内容");

这样的话,只需要创建一个工厂类,如果需要添加新的log类,只需要改动该枚举和GetLog方法就可以了,而且这样代码可读性提高了。
而且改动下一样可以用web.config进行封装。

  回复  引用  查看    
#22楼 [楼主]2006-05-06 09:49 | Terrylee      
@叫我燕哥
1.首先这里你并没有体现出使用interface的好处,在开发中可以根据实际情况来选用,这里我还是认为是用abstract class比较好,如果这些日志记录方式都有一些默认的实现时它的好处就会体现出来,你可以在看完模版方法模式之后再去思考!

2.你提出的第二个问题我就无语了。建议你仔细去学习一下面向对象设计原则的知识。Factory Method模式是很好的符合了开放-封闭原则的,经你这样一改之后,就不是Factory Method模式了,而是简单工厂模式,它违背了开放-封闭原则!

“如果需要添加新的log类,只需要改动该枚举和GetLog方法就可以了”这句话已经是违背这一原则的体现,对扩展开放,对修改封闭!

另外还有一点,我是由最开始的简单工厂模式逐渐重构出工厂方法模式的,又被你变回去了,建议你再好好读一遍我的文章!

  回复  引用  查看    
#23楼 2006-05-07 00:10 | 叫我燕哥      
首先,你的意思我看明白了,确实用工厂方法比简单工厂好,可是我觉得这是体现在整个系统同时只用一种日志记录方式的话```你这样确实无需对工厂进行改动```只用改动webconfig就可以了```
可是如果系统中有时用到File有时用到Event,那么你这样还是要在系统每个调用的时候去判断是否需要更改```和简单工厂模式一样啊````
反正不管怎么样,你的方法不比我的逊色,是我搞错了```以后还会多多请教``谢谢```
还有,有什么办法能够联系到你,想和你讨论下系统架构问题可以吗?比如QQ

  回复  引用  查看    
#24楼 [楼主]2006-05-07 09:43 | Terrylee      
@叫我燕哥
呵呵,在这篇文章里面讨论的不是日志记录组件的实际开发,仅仅是以它为例来说明工厂方法模式,实际开发中不仅仅是用一个工厂方法模式这么简单,可能需要很多模式的结合。

联系方式在我Blog的左边有:)

  回复  引用    
#25楼 2006-05-10 09:21 | ghb [未注册用户]
简明易懂,非常不错,有些问题请请教一下作者,以上EventFactory类
是否还可以抽像一次,因为在发生改变时,这个类还是必须要改变,例如现在只有Eventlog和filelog两个继承LogFactory的类,如果要再加一个datalog,那么还需要改动这个EventFactory类,还有作者是否能把源码发一份给我,ghb001@tom.com

  回复  引用    
#26楼 2006-05-10 14:47 | ghb [未注册用户]
楼主是否能将可以运行的源代码发给我一份ghb001@tom.com,我按上面的例子写了一个,但是总是不能动态声明对像,报错误factory = (LogFactory)Assembly.Load("Factory Method").CreateInstance("Factory Method." + strfactoryName);返回NULL。是否配置文件错误
  回复  引用  查看    
#27楼 [楼主]2006-05-12 08:26 | Terrylee      
@ghb
邮件已经发送~~~

你上面所说的问题我不太明白,新加一种日志记录方式,只需再有一个继承与LogFactory的DataFactory就可以了,为什么还需要修改EventFactory类呢?

  回复  引用  查看    
#28楼 2006-05-14 21:16 | Clingingboy      
好文章,不说好,对不起你
  回复  引用  查看    
#29楼 [楼主]2006-05-15 08:25 | Terrylee      
@Clingingboy
谢谢:-)

  回复  引用    
#30楼 2006-05-16 08:17 | angou [未注册用户]
确实不错,我最近也在学习架构模式和设计模式,感觉很空,这一系列文章感觉还是挺实在的,不错.
  回复  引用  查看    
#31楼 [楼主]2006-05-16 17:32 | Terrylee      
@angou
谢谢!

这个系列的文章后续还有很多,最近太忙了,更新的也比较慢了:)

  回复  引用    
#32楼 2006-05-17 14:28 | sa [未注册用户]
我有疑问请教楼主:
首先,我是新手,对设计模式没有太多研究,看了您的文章,基本理解。不过我的想法和“叫我燕哥”大致相同,可能还不如他,我想说出我的想法,请楼主指教:
1.创建LOG接口或抽象类
2.创建FILELOG和EVENTLOG类,都继承于上面的接口,并实现writer()方法
3.配置.config文件,把要具体用的日志类写在里面.
4.可以不用工厂类,嘿嘿,在客户端使用的时候直接可以用
LOG XXX=(LOG)Assembly.Load("....").CreateInstance("NameSpace." + className); 创建具体对象,然后用LOG.writer()方法写日志
上面这些是我想的,我觉得这样做更加简单方便,一目了然.
您那样的,每增加一种记录方式,又要新增工厂类,这样就要加两个文件.而我的,如果需要新增记录方式,就只需要增加一个新的类,实现LOG接口,需要使用这个新类记录日志的话只需要在.config中配置这个类,客户端不就自己创建这个对象了吗?
我知道我的想法肯定不妥,肯定是违背了设计模式或者OO的原则,不过我认为这应该是解决问题的最直接方法.难道非得遵守OO的原则而放弃最能直接解决问题的方法吗?不知这样有什么意义..
但是我还是希望自己能够做的规范,所以一定请您指出我想法中的不妥,谢谢!

  回复  引用  查看    
#33楼 [楼主]2006-05-18 08:52 | Terrylee      
@sa
这个问题我已经解释的不想再解释了,但是看见你回复了那么多,又不好意思不解释,呵呵

首先你要记住的一句话是:“系统中可变的是什么,不变的是什么”,如果这个问题没有搞清楚,其他的都是白说。如果客户端充斥着大量的这样的语句你觉得好吗?
LOG XXX=(LOG)Assembly.Load("....").CreateInstance("NameSpace." + className);

在这个例子中,变化的部分是Log,所以我们要用Factory来封装它的这种变化!

  回复  引用    
#34楼 2006-05-19 22:10 | sa [未注册用户]
明白了,谢谢,我还是需要多看看书.对不起,麻烦你啦.嘿嘿
  回复  引用  查看    
#35楼 [楼主]2006-05-22 12:15 | Terrylee      
@sa
呵呵,共同交流嘛

没什么麻烦不麻烦的:-)

  回复  引用    
#36楼 2006-06-27 17:32 | 飞鸟扬 [未注册用户]
兄弟,有个傻问题想问一下

我理解下来Abstract Factory和Factory Method的区别就是
Factory类实例化场所不一样:
Abstract Factory是在Abstract类里面实例化了不同的具体的Factory类,
Factory Method是在调用处实例化了不同的具体的Factory类。

好像Factory Method完全可以用Abstract Factory来替代的。嘿嘿,问题很傻的话也麻烦兄弟指点一下,谢谢!

  回复  引用  查看    
#37楼 [楼主]2006-06-27 17:51 | TerryLee      
  回复  引用  查看    
#38楼 2006-07-18 16:00 | 领悟      
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
在override EventLog Create()和override FileLog Create()这句是不是有问题,重写继承成员时要类型一致,上面为log而重写后返回的是FileLog ,和EventLog,虽然FileLogt和EventLog是继随Log而来的

  回复  引用  查看    
#39楼 [楼主]2006-07-18 17:56 | TerryLee      
@领悟

这样是没有问题的,FileLog、EventLog与Log之间是一种“Is-a”的关系。

  回复  引用  查看    
#40楼 2006-07-19 10:39 | 领悟      
@TerryLee
你说得有道理。我也是这样想的。但是我这样写时还是出现这样的错误:

D:\PROJECT\DesignPattern\WindowsApplication1\EventLogFactory.cs(16): “FactoryMethod.EventLogFactory.CreateLog()” : 当重写继承成员“FactoryMethod.LogFactory.CreateLog()”时,无法更改返回类型

  回复  引用  查看    
#41楼 2006-07-19 11:26 | xc#      
在这个例子中,变化的部分是Log,所以我们要用Factory来封装它的这种变化!

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


Log log = factory.Create();
log.Write();

"变化的部分是Log" 怎么理解? 在客户程序只能使用 log.Write();

  回复  引用  查看    
#42楼 2006-07-19 13:20 | xc#      
http://idior.cnblogs.com/archive/2005/04/14/137913.aspx
对于为什么要factory解释得比较好

  回复  引用  查看    
#43楼 [楼主]2006-07-20 09:12 | TerryLee      
@xc#
Log是一个抽象,“变化的部分是Log”指有可能是EventLog,也有可能是FileLog,可以看看

http://terrylee.cnblogs.com/archive/2006/01/16/318285.html

  回复  引用  查看    
#44楼 2006-07-20 09:53 | xc#      
EventLog,FileLog 都被 Log限定着,客户程序只能用Log的东西,EventLog,FileLog 是具体实现而已,
这不是factory存在的理由,关键是封装实例化逻辑,这个才是理由

  回复  引用  查看    
#45楼 [楼主]2006-07-20 10:11 | TerryLee      
@xc#

思考一个问题:封装实例化逻辑是为什么?

如果没有变化,只有一种EventLog方式,根本就不会出现第二种,还有必要封装吗?还有必要使用工厂吗?

举个例子吧:
ArrayList arr = new ArrayList();
这也涉及到了实例化,有必要封装它的实例化逻辑吗?

封装是因为会出现变化,所以我们要封装这些不稳定的部分!封装实例化逻辑仅仅说明了factory做了什么。

  回复  引用  查看    
#46楼 2006-07-20 11:31 | xc#      
封装实例化逻辑指除了new还会有其他初始化的操作,仅仅是new 用接口Log完全够了
  回复  引用  查看    
#47楼 [楼主]2006-07-20 11:53 | TerryLee      
@xc#
1.我当然知道还会有其他的初始化操作,归根结底,还是由于有变化。看来你没看明白我上面的回复!

2.“仅仅是new 用接口Log完全够了”?不会吧?
不管怎么抽象,最终你还是要创建具体的对象:
即Log log = new EventLog();
或者:Log log = new FileLog();
一旦这样写了它就存在了可变化的因素,所以需要把不稳定的部分封装起来:
Log log = LogFactory.Create();
你不可能这样写吧:Log log = new Log();
用Log怎么就够了呢??Log仅仅是一个接口!

不想再为这个问题争论下去了,到此为止吧!

  回复  引用  查看    
#48楼 2006-07-20 14:03 | 领悟      
@TerryLee
你好。我还是想问上次的那个问题。

首先我定义这样的3个类
log.cs
---------------------------------------------
public abstract class Log
{
public abstract void WriteLog();
}

FileLog.cs
---------------------------------------------
public class FileLog:Log
{
public FileLog()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override void WriteLog()
{
MessageBox.Show("写文件日志");
}
}

EventLog.cs
----------------------------------------------
public class EventLog:Log
{
public EventLog()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override void WriteLog()
{
MessageBox.Show("写事件日志");
}
}

然后定义创建对象的工厂类
LogFactory.cs
--------------------------------------
public abstract class LogFactory
{
public abstract Log CreateLog();
}


EventLogFactory.cs
--------------------------------------
public class EventLogFactory:LogFactory
{
public EventLogFactory()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override EventLog CreateLog()
{
return new EventLog();
}

}

FileLogFactory.cs
---------------------------------
public class FileLogFactory:LogFactory
{
public FileLogFactory()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override FileLog CreateLog()
{
return new FileLog();
}
}

如果这上面这样的话。就后出现这样的错误

D:\PROJECT\DesignPattern\WindowsApplication1\EventLogFactory.cs(16): “FactoryMethod.EventLogFactory.CreateLog()” : 当重写继承成员“FactoryMethod.LogFactory.CreateLog()”时,无法更改返回类型



如果我把这两个类写成这样的话就没有错误,运行正常
EventLogFactory.cs
--------------------------------------
public class EventLogFactory:LogFactory
{
public EventLogFactory()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override Log CreateLog()
{
return new EventLog();
}

}

FileLogFactory.cs
---------------------------------
public class FileLogFactory:LogFactory
{
public FileLogFactory()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override Log CreateLog()
{
return new FileLog();
}
}

  回复  引用  查看    
#49楼 [楼主]2006-07-20 14:16 | TerryLee      
@领悟

可能是我搞错了,还是用你写的最后那段代码吧:)

  回复  引用  查看    
#50楼 2006-07-20 14:51 | 领悟      
@TerryLee
你好,我也一直在学习设计模式,你写的文章很不错,你的网站我几乎每天都会打开看的。对于Factory Method模式我已经看了好多次,每一次看都有不同的理解。
对于下面这句话我也是一看再看:
在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就是要说的Factory Method模式了。

感觉自己理解了。
但是我现在用这样的一种方法也能实现上面所要的功能,感觉自己对Factory Method又不怎么理解:

具体如下:
现在我们要面临是“某个对象”的创建工作,这个对象是易变的。但有比较稳定的接口,现在就是如何来实现这样的功能使得不用改代码就可以创建不同的对象对吧.
还是按上面这个例子


我只定义3个类
Log.cs,FileLog.cs,EventLog.cs


Log.cs________________________________________________>>

using System;

namespace FactoryMethod
{
/// <summary>
/// Log 的摘要说明。
/// </summary>
public abstract class Log
{
public abstract void WriteLog();
}
}

FileLog.cs________________________________________________>>
namespace FactoryMethod
{
/// <summary>
/// FileLog 的摘要说明。
/// </summary>
public class FileLog:Log
{
public FileLog()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override void WriteLog()
{
MessageBox.Show("写文件日志");
}
}
}

EventLog.cs________________________________________________>
namespace FactoryMethod
{
/// <summary>
/// EventLog 的摘要说明。
/// </summary>
public class EventLog:Log
{
public EventLog()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public override void WriteLog()
{
MessageBox.Show("写事件日志");
}
}
}

App.config中的配置如下
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="logName" value="EventLog"></add>
</appSettings>
</configuration>


客户端的代码如下

string strlogName=System.Configuration.ConfigurationSettings.AppSettings["logName"];
Log log; log=(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);
log.WriteLog();

因为我的程序集名为WindowsApplication1所以和你的不一样,这个没有关系


运行结果为:
如果
<add key="logName" value="EventLog"></add>
测弹出对话框:写事件日志

如果
<add key="logName" value="FileLog"></add>
测弹出对话框:写文件日志

客户端的代码不用变一样实现了工厂方法模式所解决的问题。
你可以试试看。

  回复  引用  查看    
#51楼 [楼主]2006-07-20 15:21 | TerryLee      
@领悟
呵呵,不用试也知道是对的

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

  回复  引用  查看    
#52楼 2006-07-20 16:09 | 领悟      
@TerryLee
有道理,现在是真的领悟了
如果按我写的那种方式 ,如果再建对象就要这样写了.
string strlogName=System.Configuration.ConfigurationSettings.AppSettings["logName"];
Log log;
log=(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);
log.WriteLog();

Log log1;
log1=(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);
log1.WriteLog();

Log log2;
log2=(Log)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strlogName);
log2.WriteLog();

而用工厂去建的话就是

string strfactoryName = ConfigurationSettings.AppSettings["factoryName"];
LogFactory objLogFactory;
objLogFactory = (LogFactory)Assembly.Load("WindowsApplication1").CreateInstance("FactoryMethod."+strfactoryName);
Log log=objLogFactory.CreateLog();
log.WriteLog();


Log log1=objLogFactory.CreateLog();
log1.WriteLog();

Log log2=objLogFactory.CreateLog();
log2.WriteLog();
对吧。

那么这句话:
经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。

应用改成:
经常面临着“某类对象”的创建工作,由于需求的变化,这类对象的具体实现和数量经常面临着剧烈的变化,但是它却拥有比较稳定的接口。


呵呵。多谢了。

  回复  引用  查看    
#53楼 [楼主]2006-07-20 16:58 | TerryLee      
@领悟
呵呵,客气了

不过最后还是有点问题:应该还是“某个”,而不是“某类”,如果变成“某类”,就变成抽象工厂模式了。因为在这里我们并没有解决一类对象的创建问题,只是解决了单个Log对象。

  回复  引用    
#54楼 2006-08-05 10:55 | wdlgood [未注册用户]
好文章 !受教了!
能把源代码 发一份给我吗?
newsky3000@hotmail.com
麻烦了 谢谢~~

  回复  引用  查看    
#55楼 2006-08-06 02:31 | hfyb      
你好,看了你的文章,真的受益匪浅阿!我也想要一份源代码,能给我发一份吗?
hfybmail@gamil.com
谢谢了!我刚开始接触工厂设计模式,想更好的理解这个模式,所以能给我发一份吗?如果有更多的例子,也一起发给我,行吗?耽误你的时间了!非常感谢!

  回复  引用    
#56楼 2006-08-06 21:05 | 小鬼 [未注册用户]
感觉有两个东西应该改一下才是对的,不知道是不是因为我的无知而搞错了.

public class EventFactory:LogFactory
{
public override Log Create()
{
return new EventLog();
}
}
/**//// <summary>
/// FileFactory类
/// </summary>
public class FileFactory:LogFactory
{
public override Log Create()
{
return new FileLog();
}
}

  回复  引用  查看    
#57楼 [楼主]2006-08-07 08:27 | TerryLee      
@小鬼
确实应该这样修改一下:-)

  回复  引用    
#58楼 2006-08-09 14:39 | microshot [未注册用户]
看了大家的回复,受益匪浅,受益匪浅:)
  回复  引用  查看    
#59楼 2006-08-14 21:48 | 英雄=强盗      
@领悟

说得不错!不过我个人认为用简单工厂模式与反射搭配效果更好,虽然会出现需要建立多个实例时代码重复的问题,但可以通过一个简单的方法封装即可,总比增加几个类要好!

  回复  引用  查看    
#60楼 2006-08-15 17:16 | leonqin      
TerryLee 的这篇工厂方法的讲座真的挺好的,一直想在我所在的项目开发团队里推广学习一下,但他们大多数连OOP都不懂,原来都是PB程序员,直接转过来用.NET做SOA架构的应用,唉,别说模式了,程序里充斥着大量不符合OO原则的代码,真是让我头疼啊。。
  回复  引用    
#61楼 2006-08-16 00:51 | CrazyCoder [未注册用户]
笔误??

"HttpRuntime是HTTP通道的入口点,.... 它调用了一个静态的工厂方法HttpApplicationFactory.GetApplicationInstance,通过它来创建HttpContext实例。"

最后处是HttpContext还是HttpApplication?我看是后者吧。

  回复  引用  查看    
#62楼 [楼主]2006-08-16 08:19 | TerryLee      
@leonqin
谢谢支持
如果是这样,有时候确实让人头疼!

  回复  引用    
#63楼 2006-08-24 09:52 | xxw [未注册用户]
“我们知道,在应用程序中,Log对象的创建是频繁的,在这里我们可以把
LogFactory factory = new EventFactory();

这句话放在一个类模块中,任何需要用到Log对象的地方仍然不变。要是换一种日志记录方式,只要修改一处为:
LogFactory factory = new FileFactory();
其余的任何地方我们都不需要去修改。”

有问题请教:
1、如果创建的地方比较多,那么在需要把原来的EventFactory改为FileFactory的时候不是又很麻烦?这跟把原来的EventLog直接改为FileLog又有什么区别?何必要增加一个工厂类。(当然我这里暂时不考虑用反射来解决)
2、如果把创建放在一个类中,例如采用单子的模式来解决,那我也可以不需要工厂类,直接采用单件模式创建EventLog对象来用?

  回复  引用  查看    
#64楼 [楼主]2006-08-25 08:37 | TerryLee      
@xxw
1.这个问题上面有很多朋友都问过了,我已经做了解释,您可以仔细看一下上面相关的评论。

2.直接采用单件模式创建EventLog对象不是很明白,如果需要FileLog又如何呢?

  回复  引用  查看    
#65楼 2006-09-22 09:03 | 壮志      
好文章,容易理解。
  回复  引用    
#66楼 2006-09-24 02:30 | Spring[匿名] [未注册用户]
工厂类主要是负责生产EventLog和FileLog对象,如果不用工厂类来生产,直接用反射来生产EventLog和FileLog对象,然后进行Log类型的转换,不也一样吗?当然我这种想法只是在利用反射机制的情况下可以省去工厂类这步骤,否则还是不是还你介绍的更好.
  回复  引用  查看    
#67楼 [楼主]2006-09-24 16:17 | TerryLee      
@Spring[匿名]
这个问题上面的评论中我已经解释过两次了

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

  回复  引用    
#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企业级项目开发方面有所发展的话,我应该接下来再学习哪些知识呢,望楼主指点,不胜感激!


发表评论



姓名 [登录] [注册] 
主页
Email (仅博主可见) 
验证码 *  验证码看不清,换一张
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论   新用户注册   返回页首      

导航: 网站首页 社区 新闻 博问 闪存 网摘 招聘 .NET频道 知识库 找找看 Google站内搜索



China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
China-Pub 计算机绝版图书按需印刷服务

相关文章:

相关链接: