C#设计模式系列:抽象工厂模式(AbstractFactory)
1. 抽象工厂模式简介
1.1 定义
抽象工厂(Abstract Factory)模式意图:为创建一组相关或相互依赖对象提供了一个接口,而且无需指定它们的具体类。
抽象工厂可以向客户提供一个接口,是客户可以在不必指定产品具体类型的情况下,创建多个产品家族中的产品对象,它强调的“系列对象”的变化。
1.2 使用频率
高
2. 抽象工厂模式结构
2.1 结构图
2.2 参与者
抽象工厂模式参与者:
◊ AbstractFactory:声明一个创建抽象产品对象的操作接口
◊ ConcreteFactory:实现创建具体产品对象的操作
◊ AbstractProduct:声明一类产品对象接口
◊ Product
°定义一个被相应具体工厂创建的产品对象
°实现AbstractProduct接口
◊ Client:使用AbstractFactory和AbstractProduct类声明的接口
在抽象工厂模式中,产品的创建由ConcreteFactory来完成,从结构图中可以看出,抽象工厂模式的ConcreteFactory不是负责一种具体Product的创建,而是负责一个Product族的创建。
3. 抽象工厂模式结构实现
AbstractProductA.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public abstract class AbstractProductA { } }
AbstractProductB.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public abstract class AbstractProductB { public abstract void Interact(AbstractProductA a); } }
ProductA1.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public class ProductA1 : AbstractProductA { } }
ProductB1.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public class ProductB1 : AbstractProductB { public override void Interact(AbstractProductA a) { Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name); } } }
ProductA2.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public class ProductA2 : AbstractProductA { } }
ProductB2.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public class ProductB2 : AbstractProductB { public override void Interact(AbstractProductA a) { Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name); } } }
ConcreteFactory1.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public class ConcreteFactory1 : AbstractFactory { public override AbstractProductA CreateProductA() { return new ProductA1(); } public override AbstractProductB CreateProductB() { return new ProductB1(); } } }
ConcreteFactory2.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public class ConcreteFactory2 : AbstractFactory { public override AbstractProductA CreateProductA() { return new ProductA2(); } public override AbstractProductB CreateProductB() { return new ProductB2(); } } }
AbstractFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public abstract class AbstractFactory { public abstract AbstractProductA CreateProductA(); public abstract AbstractProductB CreateProductB(); } }
Client.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Structural { public class Client { private AbstractProductA _abstractProductA; private AbstractProductB _abstractProductB; public Client(AbstractFactory factory) { _abstractProductB = factory.CreateProductB(); _abstractProductA = factory.CreateProductA(); } public void Run() { _abstractProductB.Interact(_abstractProductA); } } }
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DesignPatterns.AbstractFactoryPattern.Structural; namespace DesignPatterns.AbstractFactoryPattern { class Program { static void Main(string[] args) { // Abstract factory #1 AbstractFactory factory1 = new ConcreteFactory1(); Client client1 = new Client(factory1); client1.Run(); // Abstract factory #2 AbstractFactory factory2 = new ConcreteFactory2(); Client client2 = new Client(factory2); client2.Run(); // Wait for user input Console.ReadKey(); } } }
运行输出:
ProductB1 interacts with ProductA1
ProductB2 interacts with ProductA2
请按任意键继续. . .
4. 抽象工厂模式实践应用
以KFC为例阐述抽象工厂模式的应用,假设现在KFC的食品直接没有任何关联,不可以分类,各个Product相互独立。这样工厂方法模式就可以很好解决,定义一系列的简单工厂,用户没要求一种食品就使用一个合适的简单工厂来生产相应的Product就可以。
但实际情况下,KFC的产品还可以进行套餐出售,假设KFC的产品可以分为食品Food和饮料Drink,Food和Drink分别构成了一个产品族,一个产品族就是一系列相似对象的抽象。KFC出售2种套餐,一种是经济型,包括鸡翅和可乐;另一种是豪华型,包括鸡腿和咖啡。用户只需要指出需要的套餐名即可获得相应的Food和Drink。这种情况下,工厂方法模式将不再适用,而采用抽象工厂模式进行实现。
KFCFood.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Practical { /// <summary> /// Product族1,KFC食品 /// </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.AbstractFactoryPattern.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.AbstractFactoryPattern.Practical { public class Wings : KFCFood { public override void Display() { Console.WriteLine("鸡翅 + 1"); } } }
KFCDrink.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Practical { /// <summary> /// Product族2,KFC饮料 /// </summary> public abstract class KFCDrink { public abstract void Display(); } }
Coke.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Practical { public class Coke : KFCDrink { public override void Display() { Console.WriteLine("可乐 + 1"); } } }
Coffee.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Practical { public class Coffee : KFCDrink { public override void Display() { Console.WriteLine("咖啡 + 1"); } } }
IKFCFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Practical { /// <summary> /// 抽象工厂,生产套餐 /// </summary> public interface IKFCFactory { KFCFood CreateFood(); KFCDrink CreateDrink(); } }
CheapPackageFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Practical { /// <summary> /// 经济型套餐,包括鸡翅和可乐 /// </summary> public class CheapPackageFactory : IKFCFactory { public KFCFood CreateFood() { return new Wings(); } public KFCDrink CreateDrink() { return new Coke(); } } }
LuxuryPackageFactory.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DesignPatterns.AbstractFactoryPattern.Practical { /// <summary> /// 豪华型套餐,包括鸡腿和咖啡 /// </summary> public class LuxuryPackageFactory : IKFCFactory { public KFCFood CreateFood() { return new Chicken(); } public KFCDrink CreateDrink() { return new Coffee(); } } }
Program.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DesignPatterns.AbstractFactoryPattern.Practical; namespace DesignPatterns.AbstractFactoryPattern { class Program { static void Main(string[] args) { IKFCFactory factory = new CheapPackageFactory(); KFCFood food = factory.CreateFood(); food.Display(); KFCDrink drink = factory.CreateDrink(); drink.Display(); } } }
运行输出:
鸡翅 + 1 可乐 + 1 请按任意键继续. . .
5. 抽象工厂模式应用分析
5.1 抽象工厂模式适用情形
◊ 同一个产品族的Product在一起使用时,而且它们之间是相互依赖的,不可分离
◊ 系统需要由相互关联的多个对象来构成
◊ 当想提供一组对象而不显示它们的实现过程,只显示它们的接口
◊ 系统不应当依赖一些具体Product类
5.2 抽象工厂模式的特点
◊ 隔离了具体类的生成,客户不需要知道怎样生成每一个具体Product,什么时间生成的。它将客户与具体的类分离,依赖于抽象类,耦合性低。
◊ 一个产品族中的多个对象设计成一起工作,它能保证客户端始终只使用一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说是非常实用的一种设计模式。
◊ 有利于更换产品系列,由于客户端只依赖于抽象类,更换产品系列时,只需要更改一下具体工厂名就可以。
◊ 难以支持新种类的产品,这是因为抽象工厂接口确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将引起抽象工厂类及其所有子类的改变。
5.3 抽象工厂模式与工厂方法模式区别
◊ 工厂方法模式只有一个抽象产品类,而抽象工厂模式可以有多个抽象产品类。
◊ 工厂方法模式针对一个产品等级结构,可以派生出多个具体产品类;抽象工厂模式针对面向多个产品等级结构,每个抽象产品类可以派生出多个具体产品类。