工厂方法模式是设计模式中应用最为广泛的一种。
在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却非常重要。工厂方法模式要解决的就是对象的创建时机问题。
我们可以想象一下现实中的例子:男人跟女人。他们都有吃饭、工作、睡觉这些动作,但是这些动作的具体实现肯定因性别不同而不同,比如女人吃饭一般都比较满,而男人会快一些。现在我们要在客户端生成一个人,然后执行这个人的Eat(),Work(),Sleep()这些动作,可能是在某些情况下我们会生成一个男人,其他情况下生成一个女人。怎么做呢,我们首先想到的可能是先创建两个男人、女人类:
public class Man
{
void Eat()
{
Console.WriteLine("Man is eating!");
}
void Work()
{
Console.WriteLine("Man is working!");
}
void Sleep()
{
Console.WriteLine("Man is sleeping!");
}
}
public class Woman
{
void Eat()
{
Console.WriteLine("Woman is eating!");
}
void Work()
{
Console.WriteLine("Woman is working!");
}
void Sleep()
{
Console.WriteLine("Woman is sleeping!");
}
}
然后在客户端可以这样:
static void Main(string[] args)
{
Man man= new Man();
man.Eat();
}
但是,如果我们现在不想构造男人了,而是要构造一个女人,就要把上面所有这种代码都改成:
static void Main(string[] args)
{
Woman womman = new Woman();
womman.Eat();
}
这显然是不合适的,现在我们引入工厂方法模式,这个模式涉及到的角色有:
1. 一个抽象的产品接口,工厂创建的所有产品都实现了这个接口,在本例子中我们称之为Human接口
public interface Human
{
void Eat();
void Work();
void Sleep();
}
2. 具体的产品类,在本例子中,是Man跟Woman
public class Man : Human
{
void Human.Eat()
{
Console.WriteLine("Man is eating!");
}
void Human.Work()
{
Console.WriteLine("Man is working!");
}
void Human.Sleep()
{
Console.WriteLine("Man is sleeping!");
}
}
public class Woman : Human
{
void Human.Eat()
{
Console.WriteLine("Woman is eating!");
}
void Human.Work()
{
Console.WriteLine("Woman is working!");
}
void Human.Sleep()
{
Console.WriteLine("Woman is sleeping!");
}
}
3. 抽象工厂接口,它定义了所有的具体工厂必须实现的接口,在本例子中,我们可以称之为PeopleCreator
public interface PeopleCreator
{
Human Create();
}
4. 具体的工厂,它返回的是一个具体的产品类
public class ManCreator:PeopleCreator
{
Human PeopleCreator.Create()
{
return new Man();
}
}
public class WomanCreator : PeopleCreator
{
Human PeopleCreator.Create()
{
return new Woman();
}
}
然后我们客户端可以这样写:
static void Main(string[] args)
{
PeopleCreator creator = new ManCreator();
Human people = creator.Create();
people.Work();
}
如果要生成女人的话,我们只要改将PeopleCreator creator = new ManCreator();改为 PeopleCreator creator = new WomanCreator();就可以了。
到这里,有的人可能疑问,如果这样的话,我们为什么不这样写呢:
static void Main(string[] args)
{
Human people = new Man();
people.Work();
}
这样在改为女人的时候,也是只要把Human people = new Man();改为Human people = new Womman();就可以了啊。
其实我是这样认为的,有工厂方法模式主要的是没有在客户端牵涉到具体产品类的创建,而是将这些具体产品类的创建放在了相应的具体工厂里了,这样有一个好处,就是如果在实例化一个具体产品类的时候(在本例中,就是在调用Human people = creator.Create()的时候),我现在要根据另外一个类的实例的情况来做一些特殊处理,比如决定是否真的返回一个Human实例还是返回NULL,或为这个Human实例初始化一些属性等。这是后如果是用工厂方法模式的话,我们就可以将 PeopleCreator改一下:
public interface PeopleCreator
{
Human Create(Context context);
}
再将具体工厂改一下:
public class ManCreator:PeopleCreator
{
Human PeopleCreator.Create(Context context)
{
if (context怎么样)
{
Man man = new Man();
为man做一些处理
return man;
}
}
}
这就是将产品对象的创建跟客户端代码解耦合的好处。
上一篇我们看了抽象工厂模式,这两种模式都有四个参与对象:抽象工厂,具体工厂,抽象产品,具体产品。但不同的是抽象工厂模式中,工厂生产的是一个系列的产品,就是说一个具体工厂生产这个系列产品的某种类型,另一个具体工厂生产这个系列产品的另一种类型。而工厂方法模式则只是关于一个产品的多个类型的。