概述ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就是要说的Factory Method模式了。ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
意图ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
结构图ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
生活中的例子ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
工厂方法定义一个用于创建对象的接口,但是让子类决定实例化哪个类。压注成型演示了这种模式。塑料玩具制造商加工塑料粉,将塑料注入到希望形状的模具中。玩具的类别(车,人物等等)是由模具决定的。 ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
工厂方法解说ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// 日志记录类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public class Logƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7        public void WriteEvent()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8        {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9            Console.WriteLine("EventLog Success!");ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10        }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11    ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12        public void WriteFile()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13        {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14            Console.WriteLine("FileLog Success!");ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15        }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
16ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
17        public void Write(string LogType)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
18        {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
19            switch(LogType.ToLower())ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
20            {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
21                case "event":ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
22                    WriteEvent();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
23                    break;ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
24ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
25                case "file":ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
26                    WriteFile();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
27                    break;ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
28ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
29                default:ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
30                    break;ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
31            }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
32        }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
33    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
34
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// EventLog类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public class EventLogƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public void Write()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8        Console.WriteLine("EventLog Write Success!");ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13/// FileLog类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15public class FileLogƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
16{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
17    public void Write()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
18    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
19        Console.WriteLine("FileLog Write Success!");ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
20    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
21}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
22
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

实现代码:

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// Log类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public abstract class Logƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public abstract void Write();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

此时EventLog和FileLog类的代码应该如下:

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// EventLog类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public class EventLog:Logƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public override void Write()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8        Console.WriteLine("EventLog Write Success!");ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12/// FileLog类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14public class FileLog:Logƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
16    public override void Write()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
17    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
18        Console.WriteLine("FileLog Write Success!");ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
19    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
20}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
21
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
EventLog eventlog = new EventLog();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
eventlog.Write();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// EventFactory类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public class EventFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public EventLog Create()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8        return new EventLog();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12/// FileFactory类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14public class FileFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
16    public FileLog Create()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
17    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
18        return new FileLog();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
19    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
20}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
21
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

实现代码如下:

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// LogFactory类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public abstract class LogFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public abstract Log Create();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// EventFactory类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public class EventFactory:LogFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public override EventLog Create()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8        return new EventLog();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12/// FileFactory类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14public class FileFactory:LogFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
16    public override FileLog Create()ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
17    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
18        return new FileLog();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
19    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
20}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
21
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// App类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public class Appƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public static void Main(string[] args)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8        LogFactory factory = new EventFactory();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10        Log log = factory.Create();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12        log.Write();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

LogFactory factory = new EventFactory();

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

LogFactory factory = new FileFactory();

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1<appSettings>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2    <add key="factoryName" value="EventFactory"></add>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3</appSettings>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

此时客户端代码如下:

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1/// <summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2/// App类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3/// </summary>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4public class Appƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6    public static void Main(string[] args)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7    {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8        string strfactoryName = ConfigurationSettings.AppSettings["factoryName"];ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9        ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10        LogFactory factory;ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11        factory = (LogFactory)Assembly.Load("FactoryMethod").CreateInstance("FactoryMethod."ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
+ strfactoryName);ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13        Log log = factory.Create();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14        log.Write();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15    }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
16}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
17
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ASP.NET HTTP通道中的应用ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
Factory Method模式在ASP.NET HTTP通道中我们可以找到很多的例子。ASP.NET HTTP通道是System.Web命名空间下的一个类,WEB Server使用该类处理接收到的HTTP请求,并给客户端发送响应。HTTP通道主要的工作有Session管理,应用程序池管理,缓存管理,安全等。ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

System.Web.HttpApplicationFactory

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

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
HttpApplicationFactory.GetApplicationInstance带有一个类型为HttpContext的参数,创建的所有对象(产品)都是HttpApplication的类型,通过反编译,来看一下GetApplicationInstance的实现:ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1internal static IHttpHandler GetApplicationInstance(HttpContext context)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3      if (HttpApplicationFactory._customApplication != null)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4      {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5            return HttpApplicationFactory._customApplication;ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6      }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7      if (HttpDebugHandler.IsDebuggingRequest(context))ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
8      {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
9            return new HttpDebugHandler();ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
10      }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
11      if (!HttpApplicationFactory._theApplicationFactory._inited)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
12      {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
13            lock (HttpApplicationFactory._theApplicationFactory)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
14            {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
15                  if (!HttpApplicationFactory._theApplicationFactory._inited)ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
16                  {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
17                        HttpApplicationFactory._theApplicationFactory.Init(context);ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
18                        HttpApplicationFactory._theApplicationFactory._inited = true;ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
19                  }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
20            }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
21      }ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
22      return HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
23}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
24
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
System.Web.IHttpHandlerFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
我们来做进一步的探索,HttpApplication实例需要一个Handler对象来处理资源请求, HttpApplication的主要任务就是找到真正处理请求的类。HttpApplication首先确定了一个创建Handler对象的工厂,来看一下在Machine.config文件中的配置区<httphandlers>,在配置文件注册了应用程序的具体处理类。例如在Machine.config中对*.aspx的处理将映射到System.Web.UI.PageHandlerFactory 类,而对*.ashx的处理将映射到System.Web.UI.SimpleHandlerFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
类,这两个类都是继承于IhttpHandlerFactory接口的具体类ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
<httpHandlers>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
<add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory"/>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
</httpHandlers>ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
这个配置区建立了资源请求的类型和处理请求的类之间的一个映射集。如果一个
.aspx页面发出了请求,将会调用System.Web.UI.PageHandlerFactory类,HttpApplication调用接口IHttpHandlerFactory中的工厂方法GetHandler来创建一个Handler对象。当一个名为sample.aspx的页面发出请求时,通过PageHandlerFactory将返回一个ASP.SamplePage_aspx对象(具体产品),如下图:ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’

ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
IHttpHandlerFactory工厂:ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1public interface IHttpHandlerFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2{ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3      // Methodsƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4      IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5      void ReleaseHandler(IHttpHandler handler);ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6}ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
IHttpHandlerFactory.GetHandler是一个工厂方法模式的典型例子,在这个应用中,各个角色的设置如下:ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
抽象工厂角色:IHttpHandlerFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
具体工厂角色:PageHandlerFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
抽象产品角色:IHttpHandlerƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
具体产品角色:ASP.SamplePage_aspxƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
进一步去理解ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
理解上面所说的之后,我们就可以去自定义工厂类来对特定的资源类型进行处理。第一步我们需要创建两个类去分别实现IHttpHandlerFactoryƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
IHttpHandler这两个接口。ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
1public class HttpHandlerFactoryImpl:IHttpHandlerFactory {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
2  ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
3  IHttpHandler IHttpHandlerFactory.GetHandler(ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
4      HttpContext context, String requestType, ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
5      String url, String pathTranslated ) {ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
6ƒ['²7 ‘å<www.netcsharp.cn]i[¨HPwêC’
7