1、引言
写了3篇有关设计模式的文章了,你们有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力。今天我要写第四个模式了,该模式叫抽象工厂。上一篇文章咱们讲了【工厂方法】模式,它是为了解决【简单工厂】模式所面对的问题,它的问题就是:若是咱们增长新的产品,工厂类的方法就要修改自己的代码,增长产品越多,其逻辑越复杂,同时这样的修改也是不符合【开放关闭原则OCP】,对修改代码关闭,对增长代码开放。为了解决【简单工厂】的问题,咱们引出了【工厂方法】模式,经过子类化工厂类,解决了工厂类责任的划分,产品和相应的工厂一一对应,符合了OCP。若是咱们要设计一套房子,固然咱们知道房子是由房顶、地板、窗户、房门组成的,别的组件暂时省略,先设计一套古典风格的房子,再建立一套现代风格的房子,再建立一套欧式风格的房子,这么多套房子,咱们该怎么办呢?今天咱们要讲的【抽象工厂】模式能够很好的解决多套变化的问题。
2、抽象工厂详细介绍数据库
2.一、动机(Motivate):
在软件系统中,常常面临着"一系统相互依赖的对象"的建立工做:同时,因为需求的变化,每每存在更多系列对象的建立工做。如何应对这种变化?如何绕过常规的对象建立方法(new),提供一种"封装机制"来避免客户程序和这种"多系列具体对象建立工做"的紧耦合?
2.二、意图(Intent):
提供一个建立一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 ——《设计模式》GoF设计模式
2.三、结构图(Structure)
该图是抽象工厂的UML图,结合抽象工厂的意图、动机和图示来理解该模式,今天咱们就以建设房子为例来讲明抽象工厂的实现机理。
2.四、模式的组成
能够看出,在抽象工厂模式的结构图有如下角色:ide
(1)、抽象产品类角色(AbstractProduct):为抽象工厂中相互依赖的每种产品定义抽象接口对象,也能够这样说,有几种产品,就要声明几个抽象角色,每个抽象产品角色和一种具体的产品相匹配。
(2)、具体产品类(ConcreteProduct):具体产品类实现了抽象产品类,是针对某个具体产品的实现的类型。
(3)、抽象工厂类角色(Abstract Factory):定义了建立一组相互依赖的产品对象的接口操做,每种操做和每种产品一一对应。
(4)、具体工厂类角色(ConcreteFactory):实现抽象类里面的全部抽象接口操做,能够建立某系列具体的产品,这些具体的产品是“抽象产品类角色”的子类。工具
2.五、抽象工厂的具体代码实现
随着咱们年龄的增大,咱们也到告终婚的年龄。结婚首要的问题就是房子的问题,假设我有一个颇有钱的爸爸,哈哈,有钱能够解决不少问题。做为长子的我,但愿能有一套欧式风格的房子,再加上田园风光,今生足矣。我弟弟就不同了,他想要一套现代样式的房子,若是兄弟姊妹再多年一点,那就有更多的要求了。因为房子由房顶、地板、窗户和房门组成,其余组件暂时省略,有这么多套房子要建设,每套房子的房顶、地板、窗户和房门都是一个体系的,那就让咱们看看如何使用【抽象工厂】模式来实现不一样房屋的建造。学习
1 /// <summary> 2 /// 下面以不一样系列房屋的建造为例子演示抽象工厂模式 3 /// 由于每一个人的喜爱不同,我喜欢欧式的,我弟弟就喜欢现代的 4 /// 客户端调用 5 /// </summary> 6 class Client 7 { 8 static void Main(string[] args) 9 { 10 // 哥哥的欧式风格的房子 11 AbstractFactory europeanFactory= new EuropeanFactory(); 12 europeanFactory.CreateRoof().Create(); 13 europeanFactory.CreateFloor().Create(); 14 europeanFactory.CreateWindow().Create(); 15 europeanFactory.CreateDoor().Create(); 16 17 18 //弟弟的现代风格的房子 19 AbstractFactory modernizationFactory = new ModernizationFactory(); 20 modernizationFactory.CreateRoof().Create(); 21 modernizationFactory.CreateFloor().Create(); 22 modernizationFactory.CreateWindow().Create(); 23 modernizationFactory.CreateDoor().Create(); 24 Console.Read(); 25 } 26 } 27 28 /// <summary> 29 /// 抽象工厂类,提供建立不一样类型房子的接口 30 /// </summary> 31 public abstract class AbstractFactory 32 { 33 // 抽象工厂提供建立一系列产品的接口,这里做为例子,只给出了房顶、地板、窗户和房门建立接口 34 public abstract Roof CreateRoof(); 35 public abstract Floor CreateFloor(); 36 public abstract Window CreateWindow(); 37 public abstract Door CreateDoor(); 38 } 39 40 /// <summary> 41 /// 欧式风格房子的工厂,负责建立欧式风格的房子 42 /// </summary> 43 public class EuropeanFactory : AbstractFactory 44 { 45 // 制做欧式房顶 46 public override Roof CreateRoof() 47 { 48 return new EuropeanRoof(); 49 } 50 51 // 制做欧式地板 52 public override Floor CreateFloor() 53 { 54 return new EuropeanFloor(); 55 } 56 57 // 制做欧式窗户 58 public override Window CreateWindow() 59 { 60 return new EuropeanWindow(); 61 } 62 63 // 制做欧式房门 64 public override Door CreateDoor() 65 { 66 return new EuropeanDoor(); 67 } 68 } 69 70 /// <summary> 71 /// 如今风格房子的工厂,负责建立现代风格的房子 72 /// </summary> 73 public class ModernizationFactory : AbstractFactory 74 { 75 // 制做现代房顶 76 public override Roof CreateRoof() 77 { 78 return new ModernizationRoof(); 79 } 80 81 // 制做现代地板 82 public override Floor CreateFloor() 83 { 84 return new ModernizationFloor(); 85 } 86 87 // 制做现代窗户 88 public override Window CreateWindow() 89 { 90 return new ModernizationWindow(); 91 } 92 93 // 制做现代房门 94 public override Door CreateDoor() 95 { 96 return new ModernizationDoor(); 97 } 98 } 99 100 /// <summary> 101 /// 房顶抽象类,子类的房顶必须继承该类 102 /// </summary> 103 public abstract class Roof 104 { 105 /// <summary> 106 /// 建立房顶 107 /// </summary> 108 public abstract void Create(); 109 } 110 111 /// <summary> 112 /// 地板抽象类,子类的地板必须继承该类 113 /// </summary> 114 public abstract class Floor 115 { 116 /// <summary> 117 /// 建立地板 118 /// </summary> 119 public abstract void Create(); 120 } 121 122 /// <summary> 123 /// 窗户抽象类,子类的窗户必须继承该类 124 /// </summary> 125 public abstract class Window 126 { 127 /// <summary> 128 /// 建立窗户 129 /// </summary> 130 public abstract void Create(); 131 } 132 133 /// <summary> 134 /// 房门抽象类,子类的房门必须继承该类 135 /// </summary> 136 public abstract class Door 137 { 138 /// <summary> 139 /// 建立房门 140 /// </summary> 141 public abstract void Create(); 142 } 143 144 /// <summary> 145 /// 欧式地板类 146 /// </summary> 147 public class EuropeanFloor : Floor 148 { 149 public override void Create() 150 { 151 Console.WriteLine("建立欧式的地板"); 152 } 153 } 154 155 156 /// <summary> 157 /// 欧式的房顶 158 /// </summary> 159 public class EuropeanRoof : Roof 160 { 161 public override void Create() 162 { 163 Console.WriteLine("建立欧式的房顶"); 164 } 165 } 166 167 168 /// <summary> 169 ///欧式的窗户 170 /// </summary> 171 public class EuropeanWindow : Window 172 { 173 public override void Create() 174 { 175 Console.WriteLine("建立欧式的窗户"); 176 } 177 } 178 179 180 /// <summary> 181 /// 欧式的房门 182 /// </summary> 183 public class EuropeanDoor : Door 184 { 185 public override void Create() 186 { 187 Console.WriteLine("建立欧式的房门"); 188 } 189 } 190 191 /// <summary> 192 /// 现代的房顶 193 /// </summary> 194 public class ModernizationRoof : Roof 195 { 196 public override void Create() 197 { 198 Console.WriteLine("建立现代的房顶"); 199 } 200 } 201 202 /// <summary> 203 /// 现代的地板 204 /// </summary> 205 public class ModernizationFloor : Floor 206 { 207 public override void Create() 208 { 209 Console.WriteLine("建立现代的地板"); 210 } 211 } 212 213 /// <summary> 214 /// 现代的窗户 215 /// </summary> 216 public class ModernizationWindow : Window 217 { 218 public override void Create() 219 { 220 Console.WriteLine("建立现代的窗户"); 221 } 222 } 223 224 /// <summary> 225 /// 现代的房门 226 /// </summary> 227 public class ModernizationDoor : Door 228 { 229 public override void Create() 230 { 231 Console.WriteLine("建立现代的房门"); 232 } 233 }
2.六、 抽象工厂应对需求变动
让咱们看看该模式如何应对需求的变化,假设个人表弟一看咱们的房子很好,他也想要一套古典风格的房子(哈哈,这个家伙事挺多的,有好事老是落不下他)。
ui
1 /// <summary> 2 ///先为表弟的房子来创建一个工厂类吧 3 /// </summary> 4 public class ClassicalFactory : AbstractFactory 5 { 6 //建立房顶 7 public override Roof CreateRoof() 8 { 9 return new ClassicalRoof(); 10 } 11 12 // 建立地板 13 public override Floor CreateFloor() 14 { 15 return new ClassicalFloor(); 16 } 17 18 // 建立窗户 19 public override Window CreateWindow() 20 { 21 return new ClassicalWindow(); 22 } 23 24 // 建立房门 25 public override Door CreateDoor() 26 { 27 return new ClassicalDoor(); 28 } 29 } 30 31 /// <summary> 32 ///古典的房顶 33 /// </summary> 34 public class ClassicalRoof : Roof 35 { 36 public override void Create() 37 { 38 Console.WriteLine("建立古典的房顶"); 39 } 40 } 41 42 /// <summary> 43 /// 古典的地板 44 /// </summary> 45 public class ClassicalFloor : Floor 46 { 47 public override void Create() 48 { 49 Console.WriteLine("建立古典的地板"); 50 } 51 } 52 53 /// <summary> 54 /// 古典的窗户 55 /// </summary> 56 public class ClassicalWindow : Window 57 { 58 public override void Create() 59 { 60 Console.WriteLine("建立古典的窗户"); 61 } 62 } 63 64 /// <summary> 65 /// 古典的房门 66 /// </summary> 67 public class ClassicalDoor: Door 68 { 69 public override void Create() 70 { 71 Console.WriteLine("建立古典的房门"); 72 } 73 }
此时,只须要添加五个类:一个是古典风格工厂类,负责建立古典风格的房子,另外几个类是具备古典风格的房顶、地板、窗户和房门的具体产品。从上面代码看出,抽象工厂对于系列产品的变化支持 “开放——封闭”原则(指的是要求系统对扩展开放,对修改封闭),扩展起来很是简便,可是,抽象工厂对于增长新产品这种状况就不支持”开放——封闭 “原则,由于要修改建立系列产品的抽象基类AbstractFactory,增长相应产品的建立方法,这也是抽象工厂的缺点所在。
3、抽象工厂的实现要点
一、若是没有应对“多系列对象建立”的需求变化,则没有必要使用AbstractFactory模式,这时候使用简单的静态工厂彻底能够。
二、"系列对象"指的是这些对象之间有相互依赖、或做用的关系,例如游戏开发场景中“道路”与“房屋”的依赖,“道路”与“地道”的依赖。
三、AbstractFactory模式主要在于应对“新系列”的需求变更。其缺点在于难以应对“新对象”的需求变更。
四、AbstractFactory模式常常喝FactoryMethod模式共同组合来应对“对象建立”的需求变化。
3.1】、抽象工厂模式的优势:【抽象工厂】模式将系列产品的建立工做延迟到具体工厂的子类中,咱们声明工厂类变量的时候是使用的抽象类型,同理,咱们使用产品类型也是抽象类型,这样作就尽量的能够减小客户端代码与具体产品类之间的依赖,从而下降了系统的耦合度。耦合度下降了,对于后期的维护和扩展就更有利,这也就是【抽象工厂】模式的优势所在。可能有人会说在Main方法里面(这里的代码就是客户端的使用方)仍是会使用具体的工厂类,对的。这个其实咱们经过Net的配置,把这部分移出去,最后把依赖关系放到配置文件中。若是有新的需求咱们只须要修改配置文件,根本就不须要修改代码了,让客户代码更稳定。依赖关系确定会存在,咱们要作的就是下降依赖,想彻底去除很难,也不现实。
3.2】、抽象工厂模式的缺点:有优势确定就有缺点,由于每种模式都有他的使用范围,或者说要解决的问题,不能解决的问题就是缺点了,其实也不能叫缺点了。【抽象工厂】模式很难支持增长新产品的变化,这是由于抽象工厂接口中已经肯定了能够被建立的产品集合,若是须要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及全部子类的改变,这样也就违背了“开发——封闭”原则。
3.3】、抽象工厂模式的使用场景: 若是系统须要多套的代码解决方案,而且每套的代码方案中又有不少相互关联的产品类型,而且在系统中咱们能够相互替换的使用一套产品的时候可使用该模式,客户端不须要依赖具体实现。
4、.NET中抽象工厂模式实现
微软的类库发展了这么多年,设计模式在里面有大量的应用,【抽象工厂】模式在.NET类库中也存在着大量的使用,好比和操做数据库有关的类型,这个类就是System.Data.Common.DbProviderFactory,这个类位于System.Data.dll程序集中。该类扮演抽象工厂模式中抽象工厂的角色,咱们能够用ILSpy反编译工具查看该类的实现:
/// 扮演抽象工厂的角色
/// 建立链接数据库时所须要的对象集合,
/// 这个对象集合包括有 DbConnection对象(这个是抽象产品类,如绝味例子中的YaBo类)、DbCommand类、DbDataAdapter类,针对不一样的具体工厂都须要实现该抽象类中方法,spa
1 public abstract class DbProviderFactory 2 { 3 public virtual bool CanCreateDataSourceEnumerator 4 { 5 get 6 { 7 return false; 8 } 9 } 10 11 public virtual DbCommand CreateCommand() 12 { 13 return null; 14 } 15 16 public virtual DbCommandBuilder CreateCommandBuilder() 17 { 18 return null; 19 } 20 21 public virtual DbConnection CreateConnection() 22 { 23 return null; 24 } 25 26 public virtual DbConnectionStringBuilder CreateConnectionStringBuilder() 27 { 28 return null; 29 } 30 31 public virtual DbDataAdapter CreateDataAdapter() 32 { 33 return null; 34 } 35 36 public virtual DbParameter CreateParameter() 37 { 38 return null; 39 } 40 41 public virtual CodeAccessPermission CreatePermission(PermissionState state) 42 { 43 return null; 44 } 45 46 public virtual DbDataSourceEnumerator CreateDataSourceEnumerator() 47 { 48 return null; 49 } 50 } 51 }
DbProviderFactory类是一个抽象工厂类,该类提供了建立数据库链接时所须要的对象集合的接口,实际建立的工做在其子类工厂中进行,微软使用的是SQL Server数据库,所以提供了链接SQL Server数据的具体工厂实现,具体代码能够用反编译工具查看,具体代码以下:
SqlClientFactory扮演着具体工厂的角色,用来建立链接SQL Server数据所须要的对象设计
1 public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider 2 { 3 public static readonly SqlClientFactory Instance = new SqlClientFactory(); 4 5 public override bool CanCreateDataSourceEnumerator 6 { 7 get 8 { 9 return true; 10 } 11 } 12 13 private SqlClientFactory() 14 { 15 } 16 17 public override DbCommand CreateCommand() 18 { 19 return new SqlCommand(); 20 } 21 22 public override DbCommandBuilder CreateCommandBuilder() 23 { 24 return new SqlCommandBuilder(); 25 } 26 27 public override DbConnection CreateConnection() 28 { 29 return new SqlConnection(); 30 } 31 32 public override DbConnectionStringBuilder CreateConnectionStringBuilder() 33 { 34 return new SqlConnectionStringBuilder(); 35 } 36 37 public override DbDataAdapter CreateDataAdapter() 38 { 39 return new SqlDataAdapter(); 40 } 41 42 public override DbParameter CreateParameter() 43 { 44 return new SqlParameter(); 45 } 46 47 public override CodeAccessPermission CreatePermission(PermissionState state) 48 { 49 return new SqlClientPermission(state); 50 } 51 52 public override DbDataSourceEnumerator CreateDataSourceEnumerator() 53 { 54 return SqlDataSourceEnumerator.Instance; 55 } 56 57 object IServiceProvider.GetService(Type serviceType) 58 { 59 object result = null; 60 if (serviceType == GreenMethods.SystemDataCommonDbProviderServices_Type) 61 { 62 result = GreenMethods.SystemDataSqlClientSqlProviderServices_Instance(); 63 } 64 return result; 65 } 66 }
OdbcFactory也是具体工厂类code
1 public sealed class OdbcFactory : DbProviderFactory 2 { 3 public static readonly OdbcFactory Instance = new OdbcFactory(); 4 5 private OdbcFactory() 6 { 7 } 8 9 public override DbCommand CreateCommand() 10 { 11 return new OdbcCommand(); 12 } 13 14 public override DbCommandBuilder CreateCommandBuilder() 15 { 16 return new OdbcCommandBuilder(); 17 } 18 19 public override DbConnection CreateConnection() 20 { 21 return new OdbcConnection(); 22 } 23 24 public override DbConnectionStringBuilder CreateConnectionStringBuilder() 25 { 26 return new OdbcConnectionStringBuilder(); 27 } 28 29 public override DbDataAdapter CreateDataAdapter() 30 { 31 return new OdbcDataAdapter(); 32 } 33 34 public override DbParameter CreateParameter() 35 { 36 return new OdbcParameter(); 37 } 38 39 public override CodeAccessPermission CreatePermission(PermissionState state) 40 { 41 return new OdbcPermission(state); 42 } 43 }
固然,咱们也有OleDbFactory 类型,都是负责具体的数据库操做。DbProviderFactory就是【抽象工厂】模式UML里面AbstractFactory类型。其余具体的工厂类型继承DbProviderFactory类型,这个结构很简单,我就不画图了。
5、总结
终于写完了,写了3个小时,学习设计模式不能死学,要把握核心点和使用场景。关键点第一是,面向对象设计模式的基本原则,有了原则,考虑问题就不会跑偏,而后再仔细把握每种模式的使用场景和要解决的问题,多写写代码,多看看Net的类库,它是最好的教材。面向对象设计模式