C#设计模式系列:工厂方法模式(Factory Method)
1. 工厂方法模式简介
1.1 定义
工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式是以一个类的实例化延迟到其子类。
Factory Method模式用于在不指定待创建对象的具体类的情况下创建对象。
Factory Method模式的主要意图是隐藏对象创建的复杂性。Client通常不指定要创建的具体类,Client将面向接口或抽象类进行编码,让Factory类负责创建具体的类型。通常Factory类有一个返回抽象类或者接口的静态方法。Client通常提供某种信息让Factory类使用提供的信息来确定创建并返回哪个子类。
将创建子类的责任抽象出来的好处是允许Client完全无需考虑依赖类是如何创建的,这遵守依赖倒置原则(Dependency Inversion Principle,DIP)。Factory Method模式另外一个好处是把负责对象创建的代码集中起来,如果需要修改对象生成方式,可以轻松定位并更新,而不会影响到依赖它的代码。
1.2 使用频率
高
2. 工厂方法模式结构
2.1 结构图
2.2 参与者
工厂方法模式参与者:
◊ Product:Product角色,定义工厂方法所创建的对象的接口
◊ ConcreteProduct:具体Product角色,实现Product接口
◊ Factory
° 抽象的工厂角色,声明工厂方法,该方法返回一个Product类型的对象
° Factory可以定义一个工厂方法的默认实现,返回一个默认的ConcreteProduct对象。可以调用工厂方法以创建一个Product对象。
◊ ConcreteFactory:具体的工厂角色,创建具体Product的子工厂,重写工厂方法以返回一个ConcreteProduct实例
3. 工厂方法模式结构实现
Product.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural { /// <summary> /// 定义Product抽象类,Client调用Product抽象类,并由Factory来创建具体类。 /// </summary> public abstract class Product { } }
ConcreteProductA.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural { public class ConcreteProductA : Product { } }
ConcreteProductB.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural { public class ConcreteProductB : Product { } }
Factory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural { public abstract class Factory { public abstract Product CreateProduct(); } }
ConcreteFactoryA.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural { public class ConcreteFactoryA : Factory { public override Product CreateProduct() { return new ConcreteProductA(); } } }
ConcreteFactoryB.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural { public class ConcreteFactoryB : Factory { public override Product CreateProduct() { return new ConcreteProductB(); } } }
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DesignPatterns.FactoryMethodPattern.Structural; namespace DesignPatterns.FactoryMethodPattern { class Program { static void Main(string[] args) { Factory[] factories = new Factory[2]; factories[0] = new ConcreteFactoryA(); factories[1] = new ConcreteFactoryB(); foreach (Factory factory in factories) { Product product = factory.CreateProduct(); Console.WriteLine("Created {0}", product.GetType().Name); } } } }
运行输出:
Created ConcreteProductA
Created ConcreteProductB
请按任意键继续. . .
4. 工厂方法模式实践应用
假设你现在是一家KFC的管理者,要给顾客提供一系列的食品,如鸡翅、鸡腿等,顾客没要求一种食品,KFC应当可以很快生产出来,采用工厂模式来实现这个过程。
KFCFood.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical { /// <summary> /// 抽象的KFC食品,Product角色 /// </summary> public abstract class KFCFood { public abstract void Display(); } }
Chicken.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical { public class Chicken : KFCFood { public override void Display() { Console.WriteLine("鸡腿 + 1"); } } }
Wings.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical { public class Wings : KFCFood { public override void Display() { Console.WriteLine("鸡翅 + 1"); } } }
IKFCFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical { public interface IKFCFactory { KFCFood CreateFood(); } }
ChickenFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical { public class ChickenFactory : IKFCFactory { public KFCFood CreateFood() { return new Chicken(); } } }
WingsFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical { public class WingsFactory : IKFCFactory { public KFCFood CreateFood() { return new Wings(); } } }
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DesignPatterns.FactoryMethodPattern.Practical; namespace DesignPatterns.FactoryMethodPattern { class Program { static void Main(string[] args) { // 定义一个鸡腿工厂 IKFCFactory factory = new ChickenFactory(); // 生产鸡腿 KFCFood food1 = factory.CreateFood(); food1.Display(); // 生产鸡腿 KFCFood food2 = factory.CreateFood(); food2.Display(); // 生产鸡腿 KFCFood food3 = factory.CreateFood(); food3.Display(); } } }
运行输出:
鸡腿 + 1 鸡腿 + 1 鸡腿 + 1 请按任意键继续. . .
在以上例子中,使用工厂模式的好处:
1>. 客户端在创建产品的时候只需指定一个子工厂而无需了解该子工厂具体创建什么产品;
2>. 当需求有变动,要不food1、food2、food3均改为“鸡翅”的时候,只需将
IKFCFactory factory = new ChickenFactory();
改为
IKFCFactory factory = new WingsFactory();
即可;
3>. 在工厂方法模式中,核心的工厂类不是负责所有产品的创建,而是将具体的创建工作交给子类ConcreteFactory去做。工厂类仅仅负责给出具体工厂必须实现的接口,而不涉及哪一个产品类被实例化这种细节。工厂方法模式可以使得系统在不需要修改原有代码的情况下引进新产品,如现在要增加一种新的产品“薯条”,则无需修改原有代码,只需增加一个“薯条”产品类和一个相应的“薯条”子工厂即可。在工厂方法模式中,子工厂与产品类往往具有平行的等级结构,它们之间一一对应。
5. 工厂方法模式应用分析
5.1 工厂方法模式适用情形
◊ 当一个类不知道它所必须创建的对象的类信息的时候
◊ 当一个类希望由它来指定它所创建的对象的时候
◊ 当类将创建对象的职责委托给多个辅助子类中的某一个,并且希望将哪一个辅助之类是代理者这一信息局部化的时候
5.2 工厂方法模式特点
◊ 使用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活
◊ 工厂方法模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到子类,从而提供了一种扩展的策略,较好的解决了紧耦合的关系
◊ 工厂方法模式遵守依赖倒置原则(Dependency Inversion Principle,DIP)
5.3 工厂方法模式与简单工厂模式区别
◊ 工厂方法模式和简单工厂模式在结构上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体工厂类上。工厂方法模式可以允许很多具体工厂类从抽象工厂类中将创建行为继承下来,从而可以成为多个简单工厂模式的综合,进而推广了简单工厂模式。
◊ 工厂方法模式退化后可以变得很像简单工厂模式。如果非常确定一个系统只需要一个具体工厂类,那么就不妨把抽象工厂类合并到具体的工厂类中去。由于只有一个具体工厂类,所以不妨将工厂方法改成为静态方法,这时候就得到了简单工厂模式
5.4 工厂方法模式与抽象工厂模式区别
工厂方法模式 | 抽象工厂模式 |
---|---|
只有一个抽象产品类(Product) | 有多个抽象产品类(AbstractProductA、AbstractProductA) |
具体工厂类只能创建一个具体产品类的实例。 ConcreteFactoryA生产ConcreteProductA,ConcreteFactoryB生产ConcreteProductB |
具体工厂类可以创建多个具体产品类的实例。 ConcreteFactory1生产ConcreteProductA1、ConcreteProductB1,ConcreteFactory2生产ConcreteProductA2、ConcreteProductB2 |