上次说到简单工厂模式,特点是有一个具体的类负责决定在单继承体系结构中实例化哪个子类。而工厂方法模式(Factory Method Pattern)对这种思想进行了巧妙的扩展,他不是由专门类来实例化哪个子类,相反,超类把这种决定延迟到每个子类中。这种模式实际上没有决策点,由具体应用来决定到底调用哪个。
工厂方法模式解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。工厂方法模式的对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
下面看个游泳比赛中为选手分配赛道的例子:一般实现方法
{
public override IEnumerator getSwimmers()
{
//
}
}
public class CircleSeeding
{
public override IEnumerator getSwimmers()
{
//
}
}
public IEnumerator getSeeding(string type)
{
switch (type)
{
case "pre": return new StraightSeeding().getSwimmers();
break;
case "tim": return new CircleSeeding().getSwimmers();
break;
default:
break;
}
}
为了比赛公平性,假设有很多种分配赛道的方法,上面switch语句可能很多,增加程序复杂性。因为每个规则都有getSwimmers()方法,我们可以对分配规则抽象
{
public abstract IEnumerator getSwimmers();
}
public class StraightSeeding:Seeding
{
public override IEnumerator getSwimmers()
{
//
}
}
public class CircleSeeding : Seeding
{
public override IEnumerator getSwimmers()
{
//
}
}
这样的设计满足了类之间的层次关系,又很好的符合了面向对象设计中的单一职责原则,每一个类都只负责一件具体的事情。应该说比较完美了,但这种层次关系客户端如何调用呢?
seeding.getSwimmers();
但是,当规则改变时我们又不得不修改代码。此时就需要解耦具体的分配规则和应用程序。这就要引入Factory Method模式了,每一个分配规则的对象就是工厂所生成的产品,既然有两种方式,那就需要两个不同的工厂去生产了,代码如下:
{
public Event(string fileName, int line)
{
}
public abstract Seeding getSeeding();
}
public class PreEvent : Event
{
public PreEvent(string fileName, int line)
: base(fileName, line)
{ }
public override Seeding getSeeding()
{
//关键,PreEvent返回CircleSeeding类
return new CircleSeeding();
}
}
public class TimedEvent : Event
{
public TimedEvent(string fileName, int line)
: base(fileName, line)
{ }
public override Seeding getSeeding()
{
//关键,TimedEvent返回StraightSeeding类
return new StraightSeeding();
}
}
注:这两个类继承的体系结构中,尽管看起来有一一对应的关系,但这不是必须的。实际上可能有很多中Event类,而只要很少的Seeding类。
Seeding seed = event.getSeeding();
工厂方法经常用在以下两种情况中:
第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。
第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。
最后说一下特点:
1、基础类是一个抽象类,模式必须返回一个完整的可以工作的类。
2、基类包含默认方法,除非默认方法不能胜任,才会调用这些方法。
3、可以将参数传递给工厂,告诉工厂返回那一个类型的类,这种情况下,类可以共享相同的方法名,但完成的工作可以不一样。