Abstract Factory (抽象工厂) — 【面向对象设计模式学习】
Abstract Factory (抽象工厂) — 【面向对象设计模式学习】
By CityWalker 2010年3月17日
Intent
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Applicability
a) A system should be independent of how its products are created, composed, represented.
b) A class can’t anticipate the class of objects it must create.
c) A system must use just one of a set of families of products but has more.
d) A family of related product object is designed to be used together, and you need to enforce this constraint.
Structure
Example
就以网上比较经典的Real-World例子来说吧
ClassDiagram:
抽象工厂模式中与本例中的各个对象的对应关系说明:
Abstract Factory: ContinentFactory
Concrete Factory1: AfricaFactory
Concrete Factory2: AmericaFactory
Abstract ProductA: Herbivore
Abstract ProductB: Carnivore
Concrete ProductA1: Wildebeest
Concrete ProductB1: Lion
Concrete ProductA2: Bison
Concrete ProductB2: Wolf
抽象工厂角色:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。
具体工厂角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
抽象产品角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
具体产品角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。
—— 摘自 吕震宇“C#设计模式(6)-Abstract Factory Pattern”
主要代码:
public abstract class ContinentFactory { public abstract Herbivore CreateHerbivore(); public abstract Carnivore CreateCarnivore(); }
public sealed class AfricaFactory : ContinentFactory { private static readonly AfricaFactory instance = new AfricaFactory(); AfricaFactory() { } static AfricaFactory() { } public static AfricaFactory Instance { get { return instance; } } public override Herbivore CreateHerbivore() { return new Wildebeest(); } public override Carnivore CreateCarnivore() { return new Lion(); } }
public abstract class Herbivore { } public abstract class Carnivore { public abstract void Eat(Herbivore herbivore); } public class Wildebeest : Herbivore { } public class Lion : Carnivore { public override void Eat(Herbivore herbivore) { Console.WriteLine(this + " eats " + herbivore + "\n"); } }
public class AnimalWorld { private Herbivore herbivore; private Carnivore carnivore; public AnimalWorld(ContinentFactory cf) { herbivore = cf.CreateHerbivore(); carnivore = cf.CreateCarnivore(); } public void RunFoodChain() { carnivore.Eat(herbivore); } }
Client:
ContinentFactory cf = AfricaFactory.Instance; AnimalWorld world = new AnimalWorld(cf); world.RunFoodChain(); Console.ReadKey();
一个应用中一般每个产品系列只需一个具体工厂的实例,因此,具体工厂采用Singleton模式实现。可以看出客户端并不依赖于多个产品对象的创建、组合和表达的细节,所有产品均以同样的接口出现,很好地应对了“多系列对象创建”的需求变化。
此外,Abstract Factory在增加“产品族”需求变化方面也很好地体现了“开放-封闭”原则。假如现在我要增加一个“地域族”—Asia,则只需做如下事情:
1. 增加 AsiaFactory
public sealed class AsiaFactory : ContinentFactory { private static readonly AsiaFactory instance = new AsiaFactory(); AsiaFactory() { } static AsiaFactory() { } public static AsiaFactory Instance { get { return instance; } } public override Herbivore CreateHerbivore() { return new Sheep(); } public override Carnivore CreateCarnivore() { return new Tiger(); } }
2. 增加 亚洲地区的 草食动物和肉食动物类
public class Sheep : Herbivore { } public class Tiger : Carnivore { public override void Eat(Herbivore herbivore) { Console.WriteLine("[Asia Version] —— " + this + " eats " + herbivore); } }
3. 修改客户端调用
ContinentFactory cf = AsiaFactory.Instance;
其他地方均不需要修改,此所谓“对扩展开放”。但是如果要增加新的产品,比如增加一种食肉动物或者草食动物,则需要修改所有的工厂角色,没有支持上述原则,不过正所谓“尺有所短寸有所长”每种模式其实都有它适用的情况,我们只有把握住这一点,灵活应用才是学习设计模式的最终目的。另外,对于修改客户端方面,还可以利用反射和配置文件来提高部署的灵活性,比较简单就不赘述了。
Conclusion
Benefits
a) Isolates client from concrete implementation classes. The “factory” object has the responsibility for providing creation services for entire platform family. Client never create platform object directly, they ask factory to do that for them.
b) Makes exchanging product family easy, since a concrete factory can support a complete family of products.
c) Enforces the use of products only from one family.
Liabilities
Supporting new kinds of product requires changing the AbstractFactory interface.