The GOF Abstract Factory Design Pattern In C#
--Matthew Cochran
Part I. Abstract Factory Overview
Part1.抽象工厂模式概述
The abstract factory is a GOF (Gang of Four) creational pattern where the intent is to "...provide an interface for creating families of related or dependent objects without specifying their concrete classes". ("Design Patterns" -- Gamma, Help, Johnson, Vlissides)
抽象工厂模式是一种创建型模式,意图是“提供一个创建一系列相关或相互依赖对象的接口,而不需要指定它们具体的类”。(《Design Patterns》GOF)
There are four main parts to any abstract factory:
任何抽象工厂都包含以下四大部分:
When the abstract factory is ready for consumption, we will be coding to the abstract members: the abstract factory and the abstract product. As a general rule, if our code base is abstract it should be abstract all the way. Maintenance can be a nightmare if we have concrete implementations for interfacing with some code and abstract classes and interfaces for other parts of the code (how would we then keep track of which is which and manage change?). The actual implementation will exist in the concrete factory and the concrete product.
一旦我们打定主意使用抽象工厂模式,我们就开始着着手抽象成员的编写:抽象工厂以及抽象产品。作为一般原则,如果基础代码是抽象的,那么它应该一直是抽象的。如果我们一部分代码用于实现具体界面,而另一部分代码是抽象类以及接口(那我们将如何跟踪哪一个是哪一个,以及管理变化),维护将会成为一场恶梦。实际的实现将存在于具体的工厂和具体的产品中。
The abstract factory can be implemented either through abstract base classes or interfaces. I often stand on the "interface soapbox" because it is often the best way to keep the code base flexible and have some structure at the same time. However, sometimes we don't want the rigidity that comes with a framework defined through interfaces, and so go with the alternative which is to use abstract base classes. Such is the case with the provider pattern used extensively in the .NET 2.0 framework, which is basically a configurable implementation of the abstract factory pattern. (But this is a subject for another article.)
If you have not seen it already, here's a short article I wrote on interface development.
抽象工厂既可以实现自抽象基类,也可以实现自接口。我更倾向于接口,因为这一般是保持基础代码既具有一定的结构,又具有一定的灵活性。但是,有时候我们不希望受到由接口定义的框架的束缚,而转向抽象基类。而这就要涉及到在.NET 2.0中被广泛使用的工厂方法模式,它本质上是可配置的抽象工厂模式的实现。(而这是我另一篇文章的主题了)
如果你还不是很清楚,请参考我写的一编关于接口开发的文章。
Part II. Implementation: an Abstract Automobile Factory.
Part2.实现:一个抽象的汽车工厂。
Loosely based on an article at wikipedia on the ModelT, we'll be implementing an abstract factory to build automobiles. (http://en.wikipedia.org/wiki/Ford_Model_T) I'll be taking quite a few liberties and so all of you "car people" out there will probably be wincing with my lack of automobile knowledge, but please remember, the point here is our factory, not the actual cars we make.
在一编关于ModelT的维基文章的基础上,我们将实现一个制造汽车的工厂。(http://en.wikipedia.org/wiki/Ford_Model_T) 我会有一点的随意,所以那些“汽车行家”们可能嘲笑我缺乏汽车知识,但请记住,这里的关键是我们的工厂,而不是实际生活中的汽车。
To get started, we'll look at a car in terms of four key areas: the automobile body, engine, suspension, and transmission. These are the definitions for our abstract products.
At the core of everything is our IAuto interface which defines a (very) generic automobile.
开始,我们将考虑一辆汽车的四个关键部分:主体,引擎,刹车系统以及传动装置。下面是我们的抽象产品的定义。
一切的核心的IAuto接口,它定义了一个(非常)一般的汽车。
// THE AUTOMOBILE -----------------------
interface IAuto
{
IAutoBody Body { get; }
IAutoEngine Engine { get; }
IAutoSuspension Suspension { get; }
IAutoTransmission Transmission { get; }
void Set(IAutoBody body);
void Set(IAutoEngine engine);
void Set(IAutoSuspension suspension);
void Set(IAutoTransmission transmission);
}
Next we have definitions for each of the parts:
// THE BODY ----------------------------------------
enum BodyType
{
Car,
Convertable,
Sedan,
Coupe,
Truck
}
// THE ENGINE -----------------------
// THE SUSPENSION ---------------------
// THE TRANSMISSION ----------------------
enum DriveType
{
FrontWheelDrive,
RearWheelDrive
}
enum TransmissionType
{
Manual,
Automatic
}
Finally, we'll build our definition for the abstract factory.
最后,我们将定义抽象工厂。
interface IAutoFactory
{
IAuto GetAuto();
IAutoBody CreateBody();
IAutoEngine CreateEngine();
IAutoSuspension CreateSuspension();
IAutoTransmission CreateTransmission();
}
Part III. Implementation: the Concrete Products.
Part3.实现:具体产品。
For our Model T, we need concrete definitions for the automobile and each of the parts: the engine, body, transmission and suspension.
对于ModelT,我们需要定义具体的汽车以及它的各个部分:主体,引擎,刹车系统以及传动装置。
Here is the concrete implementation of the automobile. I'm keeping it as simple as possible here, but in real life there might be all sorts of methods and properties specific to the Model T. We are only going to implement things at the bare minimum.
这里是汽车的具体定义。我将尽可能使它简单,虽然在现实生活中ModelT可能有一大堆的方法以及属性。我们只尽小地实现事物。
Keep in mind we are stripping out all the complexity that would exist in a real project and as you look through these, imagine what it would look like if, in the interface definition, there were five more properties and a dozen or so methods outlining how all the parts of the automobile interact and you can get an idea of why we would use an abstract factory for construction of multiple similar complex objects.
请记住,我们将去除所有存在于一个实际工程中的复杂性。请想像一下,如果在一个接口定义里面,有五个或更多属性,十几个或更多的方法,描述了汽车所有部分的相互关系,你就会明白为什么我们使用抽象工厂来创建大量相似的复杂对象了。
// CONCRETE AUTOMOBILE ----------------------------
Now for the definitions of the concrete components of the Model T. We'll keep these as simple as possible for the purposes of this article.
接下来是ModelT各个部件的定义。为了这篇文章我们将使其尽量简单。
// CONCRETE ENGINE -----------------------------------------
// CONCRETE BODY ---------------------------------
// CONCRETE SUSPENSION ----------------------------------------------
// CONCRETE TRANSMISSION ---------------------------
Part IV. Implementation: the Concrete Factory.
Part4.实现:具体工厂。
Finally, we need to implement the concrete factory. Notice that I have implemented the interface methods using the "virtual" keyword. This is intentional, so when we want to make a new type of ModelTFactory where there is a minor change in the Model T, we can inherit from this class and make the tweaks without having to re-write the whole factory.
最后,我们需要实现具体的工厂。请注意我在实现接口方法时使用了关键字"virtual"。这样的话,当我们因为一个极小的改变而而要实现一个新的ModelFactory时,我们可以就可以通过继承来实现这个转变,而不需要重写整个工厂了。
class ModelTFactory: IAutoFactory
{
#region IAutoFactory Members
public IAuto GetAuto()
{
return new ModelT();
}
public virtual IAutoBody CreateBody()
{
return new ModelTBody(500, BodyType.Car, 2, false);
}
public virtual IAutoEngine CreateEngine()
{
return new ModelTEngine(450, 2, 35, 100, 10, "Hand Crank");
}
public virtual IAutoSuspension CreateSuspension()
{
return new ModelTSuspension(150, 99, 56,
"transversely mounted semi-elliptical spring",
"foot pedal applied band around drum");
}
public virtual IAutoTransmission CreateTransmission()
{
return new ModelTTransmission(100, DriveType.FrontWheelDrive,
2, 2, TransmissionType.Manual);
}
#endregion
}
Part V. A Builder.
Part5.一个制造者
Now that we've covered all the bases (no pun intended), we'll create automobiles with our abstract factory using a builder method. In a more complex scenario, the builder may possibly be responsible for wiring all the different objects together if they required it. Note: The builder is not a part of the pattern definition, but it makes life much easier, so it is here.
现在我们已经实现了所有的基础(没有双关),我们将使用一个制造方法来通过抽象工厂来生产汽车。在一个更复杂的情形里,制造都可能因为需要而负责所有对象的。注意:创建者不是该模式定义的一部分,但是它让生活更简单,在这也一样。
static class AutomobileBuilder
{
public static IAuto Build(IAutoFactory factory)
{
IAuto myAuto = factory.GetAuto();
myAuto.Set(factory.CreateBody());
myAuto.Set(factory.CreateEngine());
myAuto.Set(factory.CreateSuspension());
myAuto.Set(factory.CreateTransmission());
return myAuto;
}
}
Part VI. Implementing the factory.
Part6.实现工厂。
After all the headache of creating the factory, it is actually a piece of cake to use. Check it out: To build a Model T, you only have to...
经过了创建工厂的头痛后,使用起来却很简单。尝试一下:要创建一个ModelT,你只需要:
// Build a Model T
IAutoFactory factory = new ModelTFactory();
IAuto auto = AutomobileBuilder.Build(factory);
Now, where it really shines, is when we have a new version of the Model T.
现在,如果我们一款新的ModelT,这就会变得很爽了。
In the wiki article it mentions that we can get deeper tread for the "southern road model" so we only have to override our model T factory's CreateSuspension() method and we have a new vehicle coming from our factory (notice I also gave it "anti-lock" breaks in addition to having a tread depth of 60... I know... anti-lock breaking systems weren't around then, but what's the fun in writing articles if you can't take some liberties every now and then).
在那篇维基文章中提到,我们只需要重写ModelT工厂的CreateSupension()方法来进一步得到"southern road model",这样我就从这个工厂获得了一种新的交通工具。
class SouthernRoadModelTFactory: ModelTFactory
{
public override IAutoSuspension CreateSuspension()
{
return new ModelTSuspension(150, 99, 60,
"transversely mounted semi-elliptical spring",
"anti-lock");
}
}
Not only can we adjust what kind of Model T is produced, but we can take advantage of our abstract factory to build ANY type of automobile: trucks, modern racing cars, anything you can think of.
我们不仅可以调整生产哪一款式的ModelT,我们还可以使用抽象工厂来生产各各不同的汽车:货车,赛车,以及名种各样你所能想的汽车。
Hopefully this article helped you understand the basics of the abstract factory pattern.
希望这篇文章能帮助你理解抽象工厂模式的基础。
Until next time,
Happy coding