设计模式——工厂方法模式
需求
简单工厂模式,简单地实现了对象创建工作和方法使用的分离,实现了模块的责任分配,但是所有对象的创建工作都集中到了那个工厂类里。但是,如果需要创建的对象很多,这个工厂类就会非常庞大,仍然不利于后期的代码维护,怎么办?
根据面向对象的思想,应该继续进行职责的分配和封装,也就是说,如果把每一个产品都由一个具体的工厂来创建,把简单工厂模式中那个庞大的工厂拆分成一个个小工厂类,这样每个具体的工厂类只负责某类对象的创建,职责就分配开了,这就是工厂方法模式。
定义
工厂方法模式(Factory Method pattern)相对于简单工厂模式来说,就是把一个单一的工厂类,分成了多个具体的小工厂,通过定义一个抽象的工厂父类,描述创建产品的方式,不再负责对象的创建,而具体的创建内容推迟给继承它的小实体工厂类来负责。这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂类的情况下引进新的产品。
工厂方法模式由4部分组成:(1)抽象的工厂类,描述工厂规格;(2)各个实现抽象工厂的具体工厂类;(3)抽象的产品类,描述产品规格;(4)各个实现抽象产品的具体产品类。
在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
工厂方法模式又叫做虚拟构造子(Virtual Constructor)模式或者多态性工厂模式。它使用多态性,保持了简单工厂方法的优点,同时也克服了它每次添加新产品都要改变接口的缺点。
核心的工厂类不再负责所有的产品的创建,将具体创建工作推迟到了子类,更好的支持“开—闭”原则。
工厂方法模式是最典型的模板方法模式(Templete Method pattern)应用。
案例
class Program
{
static voidMain(string[] args)
{
// 客户程序
IAnimalFactory factory = new TigerFactory();
IAnimal tiger = factory.CreateAnimal();
tiger.Eat();
IAnimalFactory factory2 = new ParrotFactory();
IAnimal parrot = factory2.CreateAnimal();
parrot.Eat();
}
}
// 抽象产品类:动物接口
public interface IAnimal
{
void Eat();
}
// 实现抽象产品类的具体产品类:老虎
public class Tiger : IAnimal
{
public void Eat()
{
Console.WriteLine("老虎会吃");
}
public void Run()
{
Console.WriteLine("老虎会跑");
}
}
// 实现抽象产品类的具体产品类:鹦鹉
public class Parrot : IAnimal
{
public void Eat()
{
Console.WriteLine("鹦鹉会吃");
}
public void Fly()
{
Console.WriteLine("鹦鹉会飞");
}
}
// 抽象工厂类:动物工厂接口
public interface IAnimalFactory
{
IAnimal CreateAnimal();
}
// 实现抽象工厂类的具体工厂类:老虎工厂
public class TigerFactory : IAnimalFactory
{
public IAnimal CreateAnimal()
{
return new Tiger();
}
}
// 实现抽象工厂类的具体工厂类:鹦鹉工厂
public class ParrotFactory : IAnimalFactory
{
public IAnimal CreateAnimal()
{
return new Parrot();
}
}
优缺点
优点:
在工厂方法模式中,客户端不再负责对象的创建,而是把这个责任推迟给了相应的具体工厂,客户端只负责对象的调用,从而明确了各个类的职责。
如果有新的产品加进来,只需要增加一个具体的创建产品的工厂类和具体的产品类就可以了,不会影响到原来已有的产品代码,后期维护更加容易,增加了系统的可扩展性。
缺点:
使用该模式需要额外的编写代码,需要慎重地考虑是否要为每个产品增加一个工厂类进行管理,从而增加代码的复杂度。
适用场景
工厂方法经常用在以下情况中:对于某个产品,客户端清楚地知道应该使用哪个具体工厂服务,进而实例化该具体工厂,生产出具体的产品来。
补充
工厂方法模式在项目中使用得非常频繁,以至于很多代码中都包含工厂方法模式。该模式几乎尽人皆知,但不是每个人都能用得好。熟能生巧,熟练掌握该模式,多思考工厂方法如何应用,而且工厂方法模式还可以与其他模式混合使用(例如模版方法模式、单例模式、原型模式等),变化出无穷的优秀设计,这也正是软件设计和开发的乐趣所在。