存在目地:工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪一个类。工厂模式有以下几种形态:
简单工厂
专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式,属于类的创建型模式。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
using System;
// 抽象产品角色,定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
public abstract class Light
{
public abstract void TurnOn();
public abstract void TurnOff();
}
// 具体产品角色,定义工厂具体加工出的对象
public class BulbLight : Light
{
public override void TurnOn()
{
Console.WriteLine("Bulb Light is Turned on");
}
public override void TurnOff()
{
Console.WriteLine("Bulb Light is Turned off");
}
}
public class TubeLight : Light
{
public override void TurnOn()
{
Console.WriteLine("Tube Light is Turned on");
}
public override void TurnOff()
{
Console.WriteLine("Tube Light is Turned off");
}
}
// 工厂类角色
public class LightSimpleFactory
{
public Light Create(string LightType)
{
if(LightType == "Bulb")
return new BulbLight();
else if(LightType == "Tube")
return new TubeLight();
else
return null;
}
}
// 客户端程序
public class Client
{
public static void Main()
{
LightSimpleFactory lsf = new LightSimpleFactory();
Light l = lsf.Create("Bulb");
l.TurnOn();
l.TurnOff();
Console.WriteLine("-----------------");
l = lsf.Create("Tube");
l.TurnOn();
l.TurnOff();
}
}
客户端免除了直接创建产品对象的责任,而仅仅"消费"产品。简单工厂模式通过这种做法实现了对责任的分割。但是系统扩展困难,一旦添加新产品就不得不修改工厂逻辑。
工厂方法
定义一个用于创建对象的接口,让子类决定实例化哪一个类,使类的实例化延迟到其子类。
在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不接触哪一个产品类被实例化这种细节。这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。一个具体工厂类对应一个具体产品类,二者往往具有平行的等级结构。
using System;
// 抽象产品类
public abstract class Light
{
public abstract void TurnOn();
public abstract void TurnOff();
}
// 具体产品类
public class BulbLight : Light
{
public override void TurnOn()
{ Console.WriteLine("Bulb Light is Turned on"); }
public override void TurnOff()
{ Console.WriteLine("Bulb Light is Turned off"); }
}
public class TubeLight : Light
{
public override void TurnOn()
{ Console.WriteLine("Tube Light is Turned on"); }
public override void TurnOff()
{ Console.WriteLine("Tube Light is Turned off"); }
}
// 抽象工厂角色,与应用程序无关具体工厂的接口
public abstract class Creator
{
public abstract Light factory();
}
// 具体工厂角色,包含与应用程序密切相关的逻辑,受到应用程序调用以创建产品对象。
public class BulbCreator : Creator
{
public override Light factory()
{ return new BulbLight(); }
}
public class TubeCreator : Creator
{
public override Light factory()
{ return new TubeLight(); }
}
// 客户端
public class Client
{
public static void Main()
{
// 增加了具体工厂对象和应用程序之间的耦合
Creator c1 = new BulbCreator();
Creator c2 = new TubeCreator();
// 避免了具体产品对象和应用程序之间的耦合
Light l1 = c1.factory();
Light l2 = c2.factory();
l1.TurnOn();
l1.TurnOff();
Console.WriteLine("-----------------");
l2.TurnOn();
l2.TurnOff();
}
}
因为具体工厂类都有共同的接口或共同的抽象父类,实现了接口多态,故又称之为多态性工厂模式。
当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体产品类以及一个具体工厂类分别继承父类,原有工厂对象不需要进行任何修改,很好的符合了"开放-封闭"原则(对扩展开放对修改封闭)。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。
抽象工厂
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。当有多个抽象产品角色时,工厂方法模式已经不能满足要求。引进抽象工厂模式, 所谓的抽象工厂是指一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象。比如微软制造键盘、鼠标、显示器,联想和中软也制造这些东西,那么键盘、鼠标、显示器就构成了一个产品族,对于其中的鼠标产品,则有微软的、有联想的、有中软的则构成了一个产品等级结构。只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一的确定这个产品。在这里一个具体工厂类就不是对应的一个具体产品类,而是一族产品。下图当产品等级结构为一维时就成了工厂方法模式。
using System;
// 抽象工厂
abstract class AbstractFactory
{
// 应包含产品族中所有的产品
// 创建抽象产品A,如鼠标
abstract public AbstractProductA CreateProductA();
// 创建抽象产品B,如键盘
abstract public AbstractProductB CreateProductB();
}
// 具体工厂1,如微软工厂,专门生产微软家族的鼠标、键盘
class ConcreteFactory1 : AbstractFactory
{
// Methods
override public AbstractProductA CreateProductA()
{
return new ProductA1();
}
override public AbstractProductB CreateProductB()
{
return new ProductB1();
}
}
// 具体工厂2,如中软工厂,专门生产中软家族的鼠标、键盘
class ConcreteFactory2 : AbstractFactory
{
// Methods
override public AbstractProductA CreateProductA()
{
return new ProductA2();
}
override public AbstractProductB CreateProductB()
{
return new ProductB2();
}
}
// 抽象产品A,如鼠标
abstract class AbstractProductA
{
abstract public void Touch();
}
// 抽象产品B,如键盘
abstract class AbstractProductB
{
abstract public void Interact();
}
// 具体产品A1,如微软的鼠标
class ProductA1 : AbstractProductA
{
override public void Touch()
{
Console.WriteLine(“微软的鼠标”);
}
}
// 具体产品B1,如微软的键盘
class ProductB1 : AbstractProductB
{
override public void Interact ()
{
Console.WriteLine(“微软的键盘”);
}
}
// 具体产品A2,如中软的鼠标
class ProductA2 : AbstractProductA
{
override public void Touch()
{
Console.WriteLine(“中软的鼠标”);
}
}
// 具体产品B2,如中软的键盘
class ProductB2 : AbstractProductB
{
override public void Interact ()
{
Console.WriteLine(“中软的键盘”);
}
}
// 客户端
class ClientApp
{
public static void Main(string[] args)
{
AbstractFactory factory = new ConcreteFactory1();
AbstractProductA productA = factory.CreateProductA();
AbstractProductB productB = factory.CreateProductB
productA.Touch();
productB.Interact();
}
}
客户端代码创建了具体工厂1微软工厂,从而通过该工厂可生产微软产品族的所有产品。但是如果需要生产中软产品,则还是需要修改客户端代码,将AbstractFactory factory = new ConcreteFactory1()改为AbstractFactory factory = new ConcreteFactory2()。解决方案是在抽象工厂类AbstractFactory里增加一个静态方法,该方法根据一个xml配置文件动态地判断应该实例化哪个具体工厂类,这样,我们就可以只对配置文件进行修改而无需修改任何代码达到要求了。
// 修改后的抽象工厂类
abstract class AbstractFactory
{
// 静态方法动态创建具体工厂类
public static AbstractFactory GetInstance()
{
// 读取xml配置文件
string factoryName = Constant.ReadXML();
AbstractFactory instance = null;
if(factoryName == "ConcreteFactory1")
{
instance = new ConcreteFactory1();
}
else if(factoryName == " ConcreteFactory2")
{
instance = new ConcreteFactory2();
}
return instance;
}
// 创建抽象产品A,如鼠标
abstract public AbstractProductA CreateProductA();
// 创建抽象产品B,如键盘
abstract public AbstractProductB CreateProductB();
}
// 客户端代码,从此无需改变
class ClientApp
{
public static void Main(string[] args)
{
AbstractFactory factory = AbstractFactory.GetInstance();
AbstractProductA productA = factory.CreateProductA();
AbstractProductB productB = factory.CreateProductB
productA.Touch();
productB.Interact();
}
}
抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,运用抽象工厂模式的关键点在于应对“多系列对象创建”的需求变化。学会了抽象工厂模式,你将理解OOP的精华:面向接口编程。
注意事项:
工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例。
参考资料:
Erich Gamma《设计模式可复用面向对象软件的基础》