抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
首先,我们想求一个形状的周长。定义一个形状的抽象类
public abstract class Shape
{
public abstract void GetPerimeter();
}
然后创建两个子类,四边形类与三角形类
public class Quadrilateral: Shape
{
public override void GetPerimeter()
{
Console.WriteLine("求四条边加起来的和");
}
}
public class Triangle : Shape
{
public override void GetPerimeter()
{
Console.WriteLine("求三条边加起来的和");
}
}
然后我们创建一个抽象工厂类与继承了抽象工厂类的三角形工厂类和四边形工厂类,他们各自的作用就是创建各自的实例
/// <summary>
/// 抽象工厂类
/// </summary>
public abstract class Creator
{
// 工厂方法
public abstract Shape CreateShape();
}
/// <summary>
/// 三角形工厂类
/// </summary>
public class TriangleFactory : Creator
{
/// <summary>
/// 负责创建三角形
/// </summary>
/// <returns></returns>
public override Shape CreateShape()
{
return new Triangle();
}
}
/// <summary>
/// 四边形工厂类
/// </summary>
public class QuadrilateralFactory : Creator
{
/// <summary>
/// 负责创建四边形
/// </summary>
/// <returns></returns>
public override Shape CreateShape()
{
return new Quadrilateral();
}
}
然后这样调用
// 初始化形状的两个工厂()
Creator triangleFactory = new TriangleFactory();
Creator quadrilateralFactory = new QuadrilateralFactory();
// 开始求三角形周长
Shapetriangle = triangleFactory.CreateShape();
triangle.GetPerimeter();
// 开始求四边形周长
Shapequadrilateral= quadrilateralFactory .CreateShape();
quadrilateral.GetPerimeter();
他的类图
应对需求变更
此时如果增加一个五边形或者六边形,我们就不需要像简单工厂一样改那个方法了,这样就会造成简单工厂的实现逻辑过于复杂,而且不符合开闭原则(对修改关闭、对扩展开发),而是去扩展几个新的类就好了。
public class Pentagon : Shape
{
public override void GetPerimeter()
{
Console.WriteLine("求五条边加起来的和");
}
}
/// <summary>
/// 五边形工厂类
/// </summary>
public class PentagonFactory : Creator
{
/// <summary>
/// 负责创建五边形
/// </summary>
/// <returns></returns>
public override Shape CreateShape()
{
return new Pentagon();
}
}
//调用方法
Creator pentagonFactory = new PentagonFactory();
// 开始求五边形周长
Shapepentagon = pentagonFactory.CreateShape();
pentagon.GetPerimeter();
他的类图
换个例子
每个具体工厂类只完成单个实例的创建,所以它具有很好的可扩展性。但是在现实生活中,一个工厂只创建单个产品这样的例子很少,因为现在的工厂都多元化了,一个工厂创建一系列的产品,如果我们要设计这样的系统时,工厂模式显然在这里不适用,然而抽象工厂模式却可以很好地解决一系列产品创建的问题。
先创建一个抽象的形状类与两个抽象子类
public abstract class Quadrilateral : Shape
{
}
public abstract class Triangle: Shape
{
}
public abstract class Shape
{
public abstract void GetArea();
}
然后创建他们的子类
/// <summary>
/// 直角三角形
/// </summary>
public class RightAngledTriangle : Triangle
{
public override void GetArea()
{
Console.Write("两条相邻边相乘除以二");
}
}
/// <summary>
/// 锐角三角形
/// </summary>
public class AcuteAngledTriangle : Triangle
{
public override void GetArea()
{
Console.Write("底乘高除以二");
}
}
/// <summary>
/// 矩形
/// </summary>
public class Rectangle : Quadrilateral
{
public override void GetArea()
{
Console.Write("两条相邻边相乘");
}
}
/// <summary>
/// 梯形
/// </summary>
public class Trapezoid : Quadrilateral
{
public override void GetArea()
{
Console.Write("上底加下底乘高除以二");
}
}
创建一个抽象工厂与两个工厂子类
/// <summary>
/// 抽象工厂类,提供创建两个形状的接口
/// </summary>
public abstract class AbstractFactory
{
public abstract Triangle CreateTriangle();
public abstract Quadrilateral CreateQuadrilateral();
}
/// <summary>
/// 直角工厂类,只创造直角
/// </summary>
public class RightAngledFactory : AbstractFactory
{
public override Quadrilateral CreateQuadrilateral()
{
return new Rectangle();
}
public override Triangle CreateTriangle()
{
return new RightAngledTriangle();
}
}
/// <summary>
/// 锐角工厂类
/// </summary>
public class AcuteAngledFactory : AbstractFactory
{
public override Quadrilateral CreateQuadrilateral()
{
return new Trapezoid();
}
public override Triangle CreateTriangle()
{
return new AcuteAngledTriangle();
}
}
调用方法
// 直角工厂求直角形状的面积
AbstractFactory rightAngledFactory = new RightAngledFactory();
Triangle rightAngledTriangle = rightAngledFactory.CreateTriangle();
rightAngledTriangle.GetArea();
Quadrilateral rectangle = rightAngledFactory.CreateQuadrilateral();
rectangle.GetArea();
// 锐角工厂求锐角形状的面积
AbstractFactory acuteAngledFactory = new AcuteAngledFactory();
Triangle acuteAngledTriangle = acuteAngledFactory.CreateTriangle();
acuteAngledTriangle.GetArea();
Quadrilateral trapezoid = acuteAngledFactory.CreateQuadrilateral();
trapezoid.GetArea();
他的类图
优点与缺点
抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展,这真是抽象工厂模式的优点所在,然后抽象模式同时也存在不足的地方。下面就具体看下抽象工厂的缺点(缺点其实在前面的介绍中以已经涉及了):
抽象工厂模式很难支持新种类产品的变化。这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了“开发——封闭”原则。
知道了抽象工厂的优缺点之后,也就能很好地把握什么情况下考虑使用抽象工厂模式了,下面就具体看看使用抽象工厂模式的系统应该符合那几个前提:
- 一个系统不要求依赖产品类实例如何被创建、组合和表达的表达,这点也是所有工厂模式应用的前提。
- 这个系统有多个系列产品,而系统中只消费其中某一系列产品
- 系统要求提供一个产品类的库,所有产品以同样的接口出现,客户端不需要依赖具体实现。
本文借鉴了《Gof设计模式》与《C#设计模式(4)——抽象工厂模式》