Provide an interface for creating familyes of related or dependent objects.
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类型。
——《设计模式:可复用面向对象软件的基础》
在介绍抽象工厂模式之前,我们先回顾下其他工厂模式的核心目标:直接由客户程序创建对象的时候,我们通过工厂把这个创建过程封装起来,让客户程序不需自己new 目标类型。
回到我们的项目实际,有时候我们要创建的不是继承自“一个”抽象类型的产品,它们本身就是多个具有一定依赖关系,但非同源的类型,因此,需要提供另一种形式的工厂,它可以产生“一系列”具有相关依赖关系的类型。
对比现实中的工厂,比如,一个中餐馆不仅提供炸酱条,还提供酸梅汤;另外一家酒店的餐厅也提供中餐,但是口味不同,提供阳春面和鲜榨果汁。如果采用工厂方法模式完成这个工作,我们可以定义INoodle和IDrink,然后再实现“阳春面”、“炸酱面”之类的不同类型,并设计不同的工厂,最后客户程序调用INoodleFactory和IDrinkFactory获得具体的食物。这个思路是可以实现的,但是太繁琐了。
我们可以换个思路,抽象出一个IRestaurant,它可以生产INoodle和IDrink,客户程序面对的是一个个“店”,通过这个“店”获得自己需要的各种食品。
抽象工厂的意图:
— 类图在此—
public interface IProduct
{
string Name { get; }
}
public interface IProduct2
{
string Name { get; }
}
public class ConcreteProductA : IProduct
{
public string Name { get { return "Product A"; } }
}
public class ConcreteProductB : IProduct
{
public string Name { get { return "Product B"; } }
}
public class ConcreteProduct2A : IProduct2
{
public string Name { get { return "Product 2A"; } }
}
public class ConcreteProduct2B : IProduct2
{
public string Name { get { return "Product 2B"; } }
}
public interface IAbstractFactory
{
IProduct CreateProduct();
IProduct2 CreateProduct2();
}
public class ConcreteFactoryA : IAbstractFactory
{
public IProduct CreateProduct()
{
return new ConcreteProductA();
}
public IProduct2 CreateProduct2()
{
return new ConcreteProduct2A();
}
}
public class ConcreteFactoryB : IAbstractFactory
{
public IProduct CreateProduct()
{
return new ConcreteProductB();
}
public IProduct2 CreateProduct2()
{
return new ConcreteProduct2B();
}
}
适用于:
硬伤:
抽象工厂模式的硬伤是,它不适合实体类型快速变化的情况。例如,如果在IProductA和IProductB以外,还需要增加一个“相关或相互依赖”的IProductC,该怎么办呢?那除了修改IAbstractFactory外,还需要修改所有的ConcreteFactory。
我们发现CreateProductA() 和 CreateProductB()的方法实在太像了,反复做这种Ctrl + C & Ctrl + V的工作实在没意思,那我们就做些修改。
public interface IAbstractFactoryWithMap
{
T Create() where T : class;
}
public class AbstractFactoryBase : IAbstractFactoryWithMap
{
protected IDictionary _Mapper;
public AbstractFactoryBase(IDictionary mapper)
{
_Mapper = mapper;
}
public T Create() where T : class
{
if (_Mapper == null || _Mapper.Count == 0||
!_Mapper.ContainsKey(typeof(T)))
throw new ArgumentException("T");
Type targetType = _Mapper[typeof(T)];
return Activator.CreateInstance(targetType) as T;
}
}
Unit Test:
private IAbstractFactoryWithMap AssemblyFactory()
{
IDictionary mapper = new Dictionary();
mapper.Add(typeof(IProduct), typeof(ConcreteProductA));
mapper.Add(typeof(IProduct2), typeof(ConcreteProduct2B));
return new AbstractFactoryBase(mapper);
}
[TestMethod]
public void Test_MapFactory()
{
IAbstractFactoryWithMap factory = this.AssemblyFactory();
IProduct product = factory.Create();
Assert.IsNotNull(product);
Assert.IsInstanceOfType(product, typeof(ConcreteProductA));
IProduct2 product2 = factory.Create();
Assert.IsNotNull(product2);
Assert.IsInstanceOfType(product2, typeof(ConcreteProduct2B));
}
通过这个改进,你也应该感觉到了,其实经典工厂模式可以通过很多方式改进,一个最直接的办法就是增加一个“Concrete Product / Abstract Product”的字典对象(TypeMapper),这个字典对象可以是通过配置文件、数据库或者其他什么方式建立,IAbstractFactory与ConcreteFactory对此并不关注。
— 类图在此 —
优势:
局限:
相对于使用依赖注入来实现对ConcreteFactory的指定,还可以转化为将Factory中的Create方法委托出去,从而解耦对ConcreteFactory的依赖。
public interface IAbstractFactoryAll
{
T1 CreateProduct();
T2 CreateProduct2();
}
public delegate IProduct ProductHandler();
public delegate IProduct2 Product2Handler();
internal class Calculator
{
public IProduct GenerateProduct()
{
ConcreteFactoryA factory = new ConcreteFactoryA();
return factory.CreateProduct();
}
public IProduct2 GenerateProduct2()
{
ConcreteFactoryB factory = new ConcreteFactoryB();
return factory.CreateProduct2();
}
}
public class DelegateFactory : IAbstractFactoryAll
{
public ProductHandler CreateProduct()
{
return new Calculator().GenerateProduct;
}
public Product2Handler CreateProduct2()
{
return new Calculator().GenerateProduct2;
}
}
Unit Test:
[TestMethod]
public void Test_DelegateFactory()
{
IAbstractFactoryAll factory = new DelegateFactory();
ProductHandler handler = factory.CreateProduct();
IProduct product = handler.Invoke();
Assert.IsNotNull(product);
Assert.IsInstanceOfType(product, typeof(ConcreteProductA));
Product2Handler handler2 = factory.CreateProduct2();
IProduct2 product2 = handler2.Invoke();
Assert.IsNotNull(product2);
Assert.IsInstanceOfType(product2, typeof(ConcreteProduct2B));
}
仿照泛型的工厂方法写了一个基于泛型的抽象工厂。
public interface IAbstractFactoryGeneric
where T1 : IProduct, new()
where T2 : IProduct2, new()
{
IProduct CreateProduct();
IProduct2 CreateProduct2();
}
public class ConcreteFactory : IAbstractFactoryGeneric
where T1 : IProduct, new()
where T2 : IProduct2, new()
{
public IProduct CreateProduct()
{
return new T1() as IProduct;
}
public IProduct2 CreateProduct2()
{
return new T2() as IProduct2;
}
}
public class GenericConcreteFactory : ConcreteFactory { }
Unit Test:
[TestMethod]
public void Test_GenericAbstractFactory()
{
GenericConcreteFactory factory = new GenericConcreteFactory();
IProduct product = factory.CreateProduct();
Assert.IsNotNull(product);
Assert.IsInstanceOfType(product, typeof(ConcreteProductA));
IProduct2 product2 = factory.CreateProduct2();
Assert.IsNotNull(product2);
Assert.IsInstanceOfType(product2, typeof(ConcreteProduct2B));
}