在上一专题中介绍了工厂方法模式,工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增长须要增长额外的代码),而工厂方法模式每一个具体工厂类只完成单个实例的建立,因此它具备很好的可扩展性。可是在现实生活中,一个工厂只建立单个产品这样的例子不多,由于如今的工厂都多元化了,一个工厂建立一系列的产品,若是咱们要设计这样的系统时,工厂方法模式显然在这里不适用,而后抽象工厂模式却能够很好地解决一系列产品建立的问题,这是本专题所要介绍的内容。html
这里首先以一个生活中抽象工厂的例子来实现一个抽象工厂,而后再给出抽象工厂的定义和UML图来帮助你们更好地掌握抽象工厂模式,同时你们在理解的时候,能够对照抽象工厂生活中例子的实现和它的定义来加深抽象工厂的UML图理解。数据库
下面就以生活中 “绝味” 连锁店的例子来实现一个抽象工厂模式。例如,绝味鸭脖想在江西南昌和上海开分店,可是因为当地人的口味不同,在南昌的全部绝味的东西会作的辣一点,而上海不喜欢吃辣的,因此上海的全部绝味的东西都不会作的像南昌的那样辣,然而这点不一样致使南昌绝味工厂和上海的绝味工厂生成全部绝味的产品都不一样,也就是某个具体工厂须要负责一系列产品(指的是绝味全部食物)的建立工做,下面就具体看看如何使用抽象工厂模式来实现这种状况。ide
1 /// <summary> 2 /// 下面以绝味鸭脖连锁店为例子演示下抽象工厂模式 3 /// 由于每一个地方的喜欢的口味不同,有些地方喜欢辣点的,有些地方喜欢吃不辣点 4 /// 客户端调用 5 /// </summary> 6 class Client 7 { 8 static void Main(string[] args) 9 { 10 // 南昌工厂制做南昌的鸭脖和鸭架 11 AbstractFactory nanChangFactory = new NanChangFactory(); 12 YaBo nanChangYabo = nanChangFactory.CreateYaBo(); 13 nanChangYabo.Print(); 14 YaJia nanChangYajia= nanChangFactory.CreateYaJia(); 15 nanChangYajia.Print(); 16 17 // 上海工厂制做上海的鸭脖和鸭架 18 AbstractFactory shangHaiFactory = new ShangHaiFactory(); 19 shangHaiFactory.CreateYaBo().Print(); 20 shangHaiFactory.CreateYaJia().Print(); 21 22 Console.Read(); 23 } 24 } 25 26 /// <summary> 27 /// 抽象工厂类,提供建立两个不一样地方的鸭架和鸭脖的接口 28 /// </summary> 29 public abstract class AbstractFactory 30 { 31 // 抽象工厂提供建立一系列产品的接口,这里做为例子,只给出了绝味中鸭脖和鸭架的建立接口 32 public abstract YaBo CreateYaBo(); 33 public abstract YaJia CreateYaJia(); 34 } 35 36 /// <summary> 37 /// 南昌绝味工厂负责制做南昌的鸭脖和鸭架 38 /// </summary> 39 public class NanChangFactory : AbstractFactory 40 { 41 // 制做南昌鸭脖 42 public override YaBo CreateYaBo() 43 { 44 return new NanChangYaBo(); 45 } 46 // 制做南昌鸭架 47 public override YaJia CreateYaJia() 48 { 49 return new NanChangYaJia(); 50 } 51 } 52 53 /// <summary> 54 /// 上海绝味工厂负责制做上海的鸭脖和鸭架 55 /// </summary> 56 public class ShangHaiFactory : AbstractFactory 57 { 58 // 制做上海鸭脖 59 public override YaBo CreateYaBo() 60 { 61 return new ShangHaiYaBo(); 62 } 63 // 制做上海鸭架 64 public override YaJia CreateYaJia() 65 { 66 return new ShangHaiYaJia(); 67 } 68 } 69 70 /// <summary> 71 /// 鸭脖抽象类,供每一个地方的鸭脖类继承 72 /// </summary> 73 public abstract class YaBo 74 { 75 /// <summary> 76 /// 打印方法,用于输出信息 77 /// </summary> 78 public abstract void Print(); 79 } 80 81 /// <summary> 82 /// 鸭架抽象类,供每一个地方的鸭架类继承 83 /// </summary> 84 public abstract class YaJia 85 { 86 /// <summary> 87 /// 打印方法,用于输出信息 88 /// </summary> 89 public abstract void Print(); 90 } 91 92 /// <summary> 93 /// 南昌的鸭脖类,由于江西人喜欢吃辣的,因此南昌的鸭脖稍微会比上海作的辣 94 /// </summary> 95 public class NanChangYaBo : YaBo 96 { 97 public override void Print() 98 { 99 Console.WriteLine("南昌的鸭脖"); 100 } 101 } 102 103 /// <summary> 104 /// 上海的鸭脖没有南昌的鸭脖作的辣 105 /// </summary> 106 public class ShangHaiYaBo : YaBo 107 { 108 public override void Print() 109 { 110 Console.WriteLine("上海的鸭脖"); 111 } 112 } 113 114 /// <summary> 115 /// 南昌的鸭架 116 /// </summary> 117 public class NanChangYaJia : YaJia 118 { 119 public override void Print() 120 { 121 Console.WriteLine("南昌的鸭架子"); 122 } 123 } 124 125 /// <summary> 126 /// 上海的鸭架 127 /// </summary> 128 public class ShangHaiYaJia : YaJia 129 { 130 public override void Print() 131 { 132 Console.WriteLine("上海的鸭架子"); 133 } 134 }
上面代码中都有详细的注释,这里就再也不解释上面的代码了,下面就具体看看抽象工厂模式的定义吧(理解定义能够参考上面的实现来加深理解):函数
抽象工厂模式:提供一个建立产品的接口来负责建立相关或依赖的对象,而不具体明确指定具体类工具
抽象工厂容许客户使用抽象的接口来建立一组相关产品,而不须要知道或关心实际生产出的具体产品是什么。这样客户就能够从具体产品中被解耦。下面经过抽象工模式的类图来了解各个类中之间的关系:ui
看完上面抽象工厂的实现以后,若是 “绝味”公司又想在湖南开一家分店怎么办呢? 由于湖南人喜欢吃麻辣的,下面就具体看看应用了抽象工厂模式的系统是如何应对这种需求的。spa
/// <summary> /// 若是绝味又想开一家湖南的分店时,由于湖南喜欢吃麻的 /// 因此这是有须要有一家湖南的工厂专门制做 /// </summary> public class HuNanFactory : AbstractFactory { // 制做湖南鸭脖 public override YaBo CreateYaBo() { return new HuNanYaBo(); } // 制做湖南鸭架 public override YaJia CreateYaJia() { return new HuNanYajia(); } } /// <summary> /// 湖南的鸭脖 /// </summary> public class HuNanYaBo : YaBo { public override void Print() { Console.WriteLine("湖南的鸭脖"); } } /// <summary> /// 湖南的鸭架 /// </summary> public class HuNanYajia : YaJia { public override void Print() { Console.WriteLine("湖南的鸭架子"); } }
public abstract class AbstractFactory { public abstract Product CreatorLine(); public abstract Product CreatorVisa(); public abstract Product CreatorTicket(); } public class ProductFactory : AbstractFactory { public override Product CreatorLine() { return new Line(); } public override Product CreatorVisa() { return new Visa(); } public override Product CreatorTicket() { return new Ticket(); } } public abstract class Product { public abstract void print(); } public class Line : Product { public override void print() { Console.WriteLine("线路产品已经建立好啦"); } } public class Ticket : Product { public override void print() { Console.WriteLine("门票产品已经建立好啦"); } } public class Visa : Product { public override void print() { Console.WriteLine("签证产品已经建立好啦"); } } public class ClientAbstract { public static void main(string[] args) { AbstractFactory factory = new ProductFactory(); factory.CreatorLine().print(); factory.CreatorTicket().print(); factory.CreatorVisa().print(); } }
此时,只须要添加三个类:一个是湖南具体工厂类,负责建立湖南口味的鸭脖和鸭架,另外两个类是具备湖南口味的鸭脖类和鸭架类。从上面代码看出,抽象工厂对于系列产品的变化支持 “开放——封闭”原则(指的是要求系统对扩展开放,对修改封闭),扩展起来很是简便,可是,抽象工厂对于添加新产品这种状况就不支持”开放——封闭 “原则,这也是抽象工厂的缺点所在,这点会在第四部分详细介绍。设计
抽象工厂模式将具体产品的建立延迟到具体工厂的子类中,这样将对象的建立封装起来,能够减小客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展,这真是抽象工厂模式的优势所在,而后抽象模式同时也存在不足的地方。下面就具体看下抽象工厂的缺点(缺点其实在前面的介绍中以已经涉及了):code
抽象工厂模式很难支持新种类产品的变化。这是由于抽象工厂接口中已经肯定了能够被建立的产品集合,若是须要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及全部子类的改变,这样也就违背了“开发——封闭”原则。htm
知道了抽象工厂的优缺点以后,也就能很好地把握什么状况下考虑使用抽象工厂模式了,下面就具体看看使用抽象工厂模式的系统应该符合那几个前提:
抽象工厂模式在实际中的应用也是至关频繁的,然而在咱们.NET类库中也存在应用抽象工厂模式的类,这个类就是System.Data.Common.DbProviderFactory,这个类位于System.Data.dll程序集中,该类扮演抽象工厂模式中抽象工厂的角色,咱们能够用reflector反编译工具查看该类的实现:
/// 扮演抽象工厂的角色
/// 建立链接数据库时所须要的对象集合,
/// 这个对象集合包括有 DbConnection对象(这个是抽象产品类,如绝味例子中的YaBo类)、DbCommand类、DbDataAdapter类,针对不一样的具体工厂都须要实现该抽象类中方法,
public abstract class DbProviderFactory { // 提供了建立具体产品的接口方法 protected DbProviderFactory(); public virtual DbCommand CreateCommand(); public virtual DbCommandBuilder CreateCommandBuilder(); public virtual DbConnection CreateConnection(); public virtual DbConnectionStringBuilder CreateConnectionStringBuilder(); public virtual DbDataAdapter CreateDataAdapter(); public virtual DbDataSourceEnumerator CreateDataSourceEnumerator(); public virtual DbParameter CreateParameter(); public virtual CodeAccessPermission CreatePermission(PermissionState state); }
DbProviderFactory类是一个抽象工厂类,该类提供了建立数据库链接时所须要的对象集合的接口,实际建立的工做在其子类工厂中进行,微软使用的是SQL Server数据库,所以提供了链接SQL Server数据的具体工厂实现,具体代码能够用反编译工具查看,具体代码以下:
/// 扮演着具体工厂的角色,用来建立链接SQL Server数据所须要的对象 public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider { // Fields public static readonly SqlClientFactory Instance = new SqlClientFactory(); // 构造函数 private SqlClientFactory() { } // 重写抽象工厂中的方法 public override DbCommand CreateCommand() { // 建立具体产品 return new SqlCommand(); } public override DbCommandBuilder CreateCommandBuilder() { return new SqlCommandBuilder(); } public override DbConnection CreateConnection() { return new SqlConnection(); } public override DbConnectionStringBuilder CreateConnectionStringBuilder() { return new SqlConnectionStringBuilder(); } public override DbDataAdapter CreateDataAdapter() { return new SqlDataAdapter(); } public override DbDataSourceEnumerator CreateDataSourceEnumerator() { return SqlDataSourceEnumerator.Instance; } public override DbParameter CreateParameter() { return new SqlParameter(); } public override CodeAccessPermission CreatePermission(PermissionState state) { return new SqlClientPermission(state); } }
由于微软只给出了链接SQL Server的具体工厂的实现,咱们也能够自定义链接Oracle、MySql的具体工厂的实现。
到这里,抽象工厂模式的介绍就结束,在下一专题就将为你们介绍建造模式。