[.NET 设计模式] Abstract Factory
类别:创建型
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
适用:
- 一个系统要独立于它的产品的创建、组合和表示时。
- 一个系统要由多个产品系列中的一个来配置时。
- 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当你提供一个产品类库,而只想显示它们的接口而不是实现时。
抽象工厂的好处是“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。”,同时它的缺点也非常明显。
1. 不支持新产品系。
2. 依赖于具体的工厂类。
3. 不能动态(不修改代码)切换产品工厂。
其实问题的核心就是对具体工厂类的依赖,使用工厂方法虽然能方便地在不同工厂间切换,但依然无法支持新产品系。
要解决这个问题,我们可以选择的方案包括:
1. 依赖注入,使用 Castle.Windsor 或者 Spring.NET 等 IoC 容器。
2. 配置反射。
当客户不再依赖具体的工厂类,我们自然可以非常方便地扩充新产品系,基于配置的方式对于动态切换工厂自然也很简单。
1. 配置反射
namespace ConsoleApplication1
{
interface IProduct
{
}
abstract class AbstractFactory
{
public abstract IProduct NewProduct();
public static AbstractFactory GetFactory()
{
string typeName = ConfigurationManager.AppSettings["factory"];
Type type = Type.GetType(typeName);
return Activator.CreateInstance(type) as AbstractFactory;
}
}
class ProductA : IProduct
{
}
class FactoryA : AbstractFactory
{
public override IProduct NewProduct()
{
return new ProductA();
}
}
public class Program
{
static void Main(string[] args)
{
IProduct p = AbstractFactory.GetFactory().NewProduct();
}
}
}
{
interface IProduct
{
}
abstract class AbstractFactory
{
public abstract IProduct NewProduct();
public static AbstractFactory GetFactory()
{
string typeName = ConfigurationManager.AppSettings["factory"];
Type type = Type.GetType(typeName);
return Activator.CreateInstance(type) as AbstractFactory;
}
}
class ProductA : IProduct
{
}
class FactoryA : AbstractFactory
{
public override IProduct NewProduct()
{
return new ProductA();
}
}
public class Program
{
static void Main(string[] args)
{
IProduct p = AbstractFactory.GetFactory().NewProduct();
}
}
}
app.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="factory" value="ConsoleApplication1.FactoryA, ConsoleApplication1"/>
</appSettings>
</configuration>
<configuration>
<appSettings>
<add key="factory" value="ConsoleApplication1.FactoryA, ConsoleApplication1"/>
</appSettings>
</configuration>
这个例子中,我们使用反射动态创建一个具体工厂,从而实现了客户对具体工厂依赖的解耦。由于具体工厂信息存储在配置文件中,因此我们随时都可以切换工厂,当然包括我们新增的工厂和产品系,而无需修改客户代码。
2. IoC
其实从本质上说,IoC所使用的手段和反射基本相同,只是IoC一般提供更强大的配置能力以及生命期管理。多数IoC缺省生命模式就是Singleton,省了我们为工厂提供单件模式的代码。
下面的例子使用了 Castle.Windsor,至于 Spring.NET 也很简单,本贴省略(可以参考本Blog有关Spring.NET的相关文章)。
namespace ConsoleApplication1
{
interface IProduct
{
}
abstract class AbstractFactory
{
public abstract IProduct NewProduct();
public static AbstractFactory GetFactory()
{
IWindsorContainer provider = new WindsorContainer(@"Ioc.xml");
return provider["factory"] as AbstractFactory;
}
}
class ProductA : IProduct
{
}
class FactoryA : AbstractFactory
{
public override IProduct NewProduct()
{
return new ProductA();
}
}
public class Program
{
static void Main(string[] args)
{
IProduct p = AbstractFactory.GetFactory().NewProduct();
}
}
}
{
interface IProduct
{
}
abstract class AbstractFactory
{
public abstract IProduct NewProduct();
public static AbstractFactory GetFactory()
{
IWindsorContainer provider = new WindsorContainer(@"Ioc.xml");
return provider["factory"] as AbstractFactory;
}
}
class ProductA : IProduct
{
}
class FactoryA : AbstractFactory
{
public override IProduct NewProduct()
{
return new ProductA();
}
}
public class Program
{
static void Main(string[] args)
{
IProduct p = AbstractFactory.GetFactory().NewProduct();
}
}
}
Ioc.xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<components>
<component id="factory" type="ConsoleApplication1.FactoryA, ConsoleApplication1">
</component>
</components>
</configuration>
<configuration>
<components>
<component id="factory" type="ConsoleApplication1.FactoryA, ConsoleApplication1">
</component>
</components>
</configuration>