五.创建型设计模式——Abstract Factory Pattern(抽象工厂模式)
-
定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂(Abstract Factory)模式又称为Kit模式,属于对象创建型模式。
抽象工厂模式与工厂方法模式最大的区别在于:工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则针对的是多个产品等级结构。正因如此,在抽象工厂模式中经常会用到产品族(Product Family)这一概念,它指的是位于不同的产品登记结构中,并且功能互相关联的产品系列,如下图:
图上三个箭头所指就是三个功能湘湖关联的产品,它们位于三个不同的产品登记结构中的相同位置上,共同组成了一个产品族。抽象工厂就是要生成这样的产品族。而在这种产品族中,各产品之间有关联耦合,抽象工厂会将这种关联耦合设计成一个抽象类。抽象工厂模式符合GRASP的纯虚构模式,同事取得高内聚低耦合的效果。
其UML类图如下:
其中的类或对象之间的关系为:
1. AbstractFactory(抽象工厂):声明生成抽象产品的方法。
2. ConcreteFactory(具体工厂):执行生成抽象产品的方法,生成一个具体的产品。
3. AbstractProduct(抽象产品):为一种产品声明接口。
4. Product(具体产品):定义具体工厂生成的具体产品的对象,实现产品接口。
5. Clint(客户):我们的应用程序,使用抽象产品和抽象工厂生成对象。
典型应用的顺序图如下:
抽象工厂负责创建不同的有联系的多个产品,不同的抽象工厂创建的产品不同,但产品之间的关系相同,抽象工厂是GRASP模式的纯虚构的表现。
-
实例1——大陆生态系统
大家都知道,动物世界中各大陆的动物是不一样的,各种动物可以分成两样,一种食草,一种食肉。食肉的动物吃食草动物。美洲狼属于食肉动物,野牛属于食草动物,美洲狼猎吃野牛;非洲的狮子属于食肉动物,角马属于食草动物,狮子猎吃角马。类的关系图如下:
//抽象大陆工厂
abstract class ContinentFacctory
{
abstract public Herbivore CreateHerbivore();
abstract public Carnivore CreateCarnivore();
}
//非洲大陆,有角马、狮子
class AfricaFactory : ContinentFacctory
{
public override Herbivore CreateHerbivore()
{
return new Wildebeest();
}
public override Carnivore CreateCarnivore()
{
return new Lion();
}
}
//美洲大陆,有野牛、狼
class AmericaFactory : ContinentFacctory
{
public override Herbivore CreateHerbivore()
{
return new Bison();
}
public override Carnivore CreateCarnivore()
{
return new Wolf();
}
}
//食草动物
abstract class Herbivore { }
//食肉动物
abstract class Carnivore
{
abstract public void Eat(Herbivore h);
}
//角马
class Wildebeest : Herbivore { }
//狮子
class Lion : Carnivore
{
public override void Eat(Herbivore h)
{
Console.WriteLine(this + " eats" + h);
}
}
//野牛
class Bison : Herbivore { }
//狼
class Wolf : Carnivore
{
public override void Eat(Herbivore h)
{
Console.WriteLine(this + " eats" + h);
}
}
//动物世界
class AnimalWorld
{
private Herbivore herbivore;
private Carnivore carnivore;
//创建两种动物分类
public AnimalWorld(ContinentFacctory factory)
{
carnivore = factory.CreateCarnivore();
herbivore = factory.CreateHerbivore();
}
//运行食物链
public void RunFoodChain()
{
carnivore.Eat(herbivore);
}
}
//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
//创造并运行非洲动物世界
ContinentFacctory africa = new AfricaFactory();
AnimalWorld world = new AnimalWorld(africa);
world.RunFoodChain();
//创造兵运行美洲动物世界
ContinentFacctory america = new AmericaFactory();
world = new AnimalWorld(america);
world.RunFoodChain();
Console.Read();
}
}
-
实例2——电脑产品
IBM,Dell都是著名的计算机生产厂家,他们采用的主办、硬盘及CPU。但配件间、主板与CPU一定要互相兼容例如下面例子中的微星MSIK7N2G配AMD的CPU;微星MSI865PE配Intel的CPU。类图如下:
//定义CPU接口
public interface iCPU
{
string GetCPU();
}
//定义AMD类,实现CPU接口
public class AMD : iCPU
{
public string GetCPU()
{
return "Athlon XP 2800+";
}
}
//定义Intel类,实现CPU接口
public class Intel : iCPU
{
public string GetCPU()
{
return "奔腾4 3.2C";
}
}
//定义硬盘接口
public interface iHardDisc
{
string GetSize();
}
//定义Maxtor类,实现硬盘接口
public class Maxtor : iHardDisc
{
public string GetSize()
{
return "MaXLine Plus II 200G";
}
}
//定义WestDigit类,实现硬盘接口
public class WestDigit : iHardDisc
{
public string GetSize()
{
return "WD2500JD 250G";
}
}
//定义主板接口,包含参数为iCPU的公共方法Attach()
public interface iMainBoard
{
void Attach(iCPU cpu);
}
//主板微星MSI865PE,支持Intel的CPU
public class MSI865PE : iMainBoard
{
public void Attach(iCPU icpu)
{
if (icpu.GetType().Name.ToLower() == "intel")
Console.WriteLine("MSI865PE");
else
throw new Exception("主板MSI865PE只能配Intel的CPU");
}
}
//主板微星MSIK7N2G,支持AMD的CPU
public class MSIK7N2G : iMainBoard
{
public void Attach(iCPU icpu)
{
if (icpu.GetType().Name.ToLower() == "amd")
Console.WriteLine("MSIK7N2G");
else
throw new Exception("主板MSIK7N2G只能配AMD的CPU");
}
}
//定义抽象电脑工厂类
public abstract class ComputerFactory
{
protected iCPU icpu;
protected iHardDisc iHD;
protected iMainBoard iMB;
public void Show()
{
try
{
Console.WriteLine(this.GetType().Name + "生产的电脑配置");
Console.WriteLine("CPU:" + icpu.GetCPU());
Console.WriteLine("HardDisk:" + iHD.GetSize());
Console.WriteLine("MainBoard:");
iMB.Attach(icpu);
}
catch( Exception e)
{
Console.Error.WriteLine(e.Message);
}
}
}
//抽象电脑工厂类派生类IBM,定义其返回的系列配件产品
public class IBM : ComputerFactory
{
public IBM()
{
icpu = new Intel();
iHD = new WestDigit();
iMB = new MSI865PE();
}
}
//抽象电脑工厂类派生类DELL,定义其返回的系列配件产品
public class Dell : ComputerFactory
{
public Dell()
{
icpu = new AMD();
iHD = new Maxtor();
iMB = new MSIK7N2G();
}
}
//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
IBM ibm = new IBM();
ibm.Show();
Dell dell = new Dell();
dell.Show();
Console.Read();
}
}
-
优势和缺陷
抽象工厂模式的主要优点是隔离了具体类的生成,使得客户不需要知道什么被创建了。犹豫这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变这个软件的系统的行为。另外,应用抽象工厂模式符合GRASP纯虚构的模式,可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛应用。
使用抽象工厂模式的最大好处是,当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是非常使用的一种设计模式。
抽象工厂模式的确定是,在添加新的产品对象时,难易扩展抽象工厂以便生产新种类的产品。这是因为AbstractFatory接口规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对AbstractFatory及其所有子类的修改,显然有小小的不便,但不重要。
-
应用情景
下面的情景很适合应用抽象工厂模式:
1. 系统需要屏蔽有关对象如何创建、如何组织和如何表示。
2. 系统需要由关联的多个对象来构成。
3. 有关联的多个对象需要一起应用并且它们的约束是强迫的(不可分离)。
4. 你想提供一组对象而不显示他们的实现过程,只显示它们的接口。