创建模式
使用创建模式的主要动机来自于“变化”,应用的哪些组成会快速变化呢?不一定,多数项目会有一个相对稳定的核心,无论是被叫做Framework,还是更时髦,感觉更底层的Foundation,这个部分相对比较稳定,言外之意其他部分都会“相对”变化比较频繁。
创建模式抽象了实例化过程。它们帮组一个系统独立于如何创建、组合和表示对象。一个类创建模式使用继承改变被实例化的类,而一个对象创建模式将实例化委托给另外一个对象。
随着系统的演化,越来越依赖于对象复合而不是类继承,创建模式变得更为重要。
1. 预备役——简单工厂
最简单的工厂类
作为一个预备役,首先用朴实的方法实现一个工厂。
public interface IProduct
{
string Name { get; }
}
public class ConcreteProductA : IProduct
{
public string Name { get { return "Product A"; } }
}
public class SimpleFactory
{
public IProduct Create()
{
return new ConcreteProductA();
}
}
Unit Test:
[TestMethod]
public void Test_SimpleFactory()
{
SimpleFactory factory = new SimpleFactory();
IProduct product = factory.Create();
Assert.IsNotNull(product);
Assert.IsInstanceOfType(product, typeof(ConcreteProductA));
}
优点:
- 通过IProduct隔离Client与具体ContreteProductX的依赖关系,在客户程序视野中根本就没有ContreteProductX。
- 即使ContreteProductX增加、删除方法或属性,也无妨大局,只要按照要求实现了IProduct就可以,Client无需关心ContreteProductX的变化。
缺点:
- 相对于直接写ContreteProductX而言,要平白地多写一个工厂出来。
- 效率问题。如果构建一个Factory实例,并用它获取一个抽象类型实例后就不再使用,资源上有些浪费,尤其当这个过程非常频繁的时候。
改进:
- 把工厂实例作为参数注入到操作中,而不是在每个方法内部自行创建。
- 把工厂设计为单例方式,因为工厂的指责相对单一,所有客户端需要的工厂使用的都是一个唯一的共享实例。
- 使用静态类。这也算是一个有效节省资源使用的途径,不过切记:静态类不能被继承它只能从Object继承,没有其他可能。这个有些违反面向对象的设计原则,同时也会为测试的数据隔离工作带来了很大的障碍。
扩展
参数化工厂
如果想让工厂在运行时有效选择符合抽象类型要求的某个实例,最简单的机制莫过于传递一个参数,它可能是一个字符串,一个枚举值,例如在工厂类的实现中显示的传递一个Cat
egory类型的枚举参数。
public interface IProduct
{
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 ParametricFactory
{
public enum Category
{
A,
B
}
public IProduct Create(Category category)
{
switch(category)
{
case Category.A:
return new ConcreteProductA();
case Category.B:
return new ConcreteProductB();
default:
throw new NotSupportedException();
}
}
}
Unit Test:
[TestMethod]
public void Test_ParametricFactory()
{
ParametricFactory factory = new ParametricFactory();
IProduct product = factory.Create(ParametricFactory.Category.A);
Assert.IsNotNull(product);
Assert.IsInstanceOfType(product, typeof(ConcreteProductA));
product = factory.Create(ParametricFactory.Category.B);
Assert.IsNotNull(product);
Assert.IsInstanceOfType(product, typeof(ConcreteProductB));
}