一、引言
写了3篇有关设计模式的文章了,大家有了些反馈,说能从中学到一些东西,我感到很欣慰,那就继续努力。今天我要写第四个模式了,该模式叫抽象工厂。上一篇文章我们讲了【工厂方法】模式,它是为了解决【简单工厂】模式所面对的问题,它的问题就是:如果我们增加新的产品,工厂类的方法就要修改本身的代码,增加产品越多,其逻辑越复杂,同时这样的修改也是不符合【开放关闭原则OCP】,对修改代码关闭,对增加代码开放。为了解决【简单工厂】的问题,我们引出了【工厂方法】模式,通过子类化工厂类,解决了工厂类责任的划分,产品和相应的工厂一一对应,符合了OCP。如果我们要设计一套房子,当然我们知道房子是由房顶、地板、窗户、房门组成的,别的组件暂时省略,先设计一套古典风格的房子,再创建一套现代风格的房子,再创建一套欧式风格的房子,这么多套房子,我们该怎么办呢?今天我们要讲的【抽象工厂】模式可以很好的解决多套变化的问题。二、抽象工厂详细介绍2.1、动机(Motivate):
在软件系统中,经常面临着"一系统相互依赖的对象"的创建工作:同时,由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种"封装机制"来避免客户程序和这种"多系列具体对象创建工作"的紧耦合? 2.2、意图(Intent): 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 ——《设计模式》GoF2.3、结构图(Structure)
该图是抽象工厂的UML图,结合抽象工厂的意图、动机和图示来理解该模式,今天我们就以建设房子为例来说明抽象工厂的实现机理。2.4、模式的组成 可以看出,在抽象工厂模式的结构图有以下角色:(1)、抽象产品类角色(AbstractProduct):为抽象工厂中相互依赖的每种产品定义抽象接口对象,也可以这样说,有几种产品,就要声明几个抽象角色,每一个抽象产品角色和一种具体的产品相匹配。
(2)、具体产品类(ConcreteProduct):具体产品类实现了抽象产品类,是针对某个具体产品的实现的类型。 (3)、抽象工厂类角色(Abstract Factory):定义了创建一组相互依赖的产品对象的接口操作,每种操作和每种产品一一对应。 (4)、具体工厂类角色(ConcreteFactory):实现抽象类里面的所有抽象接口操作,可以创建某系列具体的产品,这些具体的产品是“抽象产品类角色”的子类。 2.5、抽象工厂的具体代码实现 随着我们年龄的增大,我们也到了结婚的年龄。结婚首要的问题就是房子的问题,假设我有一个很有钱的爸爸,哈哈,有钱可以解决很多问题。作为长子的我,希望能有一套欧式风格的房子,再加上田园风光,此生足矣。我弟弟就不一样了,他想要一套现代样式的房子,如果兄弟姊妹再多年一点,那就有更多的要求了。由于房子由房顶、地板、窗户和房门组成,其他组件暂时省略,有这么多套房子要建设,每套房子的房顶、地板、窗户和房门都是一个体系的,那就让我们看看如何使用【抽象工厂】模式来实现不同房屋的建造。1 ///2 /// 下面以不同系列房屋的建造为例子演示抽象工厂模式 3 /// 因为每个人的喜好不一样,我喜欢欧式的,我弟弟就喜欢现代的 4 /// 客户端调用 5 /// 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 ///29 /// 抽象工厂类,提供创建不同类型房子的接口 30 /// 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 ///41 /// 欧式风格房子的工厂,负责创建欧式风格的房子 42 /// 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 ///71 /// 现在风格房子的工厂,负责创建现代风格的房子 72 /// 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 ///101 /// 房顶抽象类,子类的房顶必须继承该类102 /// 103 public abstract class Roof104 {105 ///106 /// 创建房顶107 /// 108 public abstract void Create();109 }110 111 ///112 /// 地板抽象类,子类的地板必须继承该类113 /// 114 public abstract class Floor115 {116 ///117 /// 创建地板118 /// 119 public abstract void Create();120 }121 122 ///123 /// 窗户抽象类,子类的窗户必须继承该类124 /// 125 public abstract class Window126 {127 ///128 /// 创建窗户129 /// 130 public abstract void Create();131 }132 133 ///134 /// 房门抽象类,子类的房门必须继承该类135 /// 136 public abstract class Door137 {138 ///139 /// 创建房门140 /// 141 public abstract void Create();142 }143 144 ///145 /// 欧式地板类146 /// 147 public class EuropeanFloor : Floor148 {149 public override void Create()150 {151 Console.WriteLine("创建欧式的地板");152 }153 }154 155 156 ///157 /// 欧式的房顶158 /// 159 public class EuropeanRoof : Roof160 {161 public override void Create()162 {163 Console.WriteLine("创建欧式的房顶");164 }165 }166 167 168 ///169 ///欧式的窗户170 /// 171 public class EuropeanWindow : Window172 {173 public override void Create()174 {175 Console.WriteLine("创建欧式的窗户");176 }177 }178 179 180 ///181 /// 欧式的房门182 /// 183 public class EuropeanDoor : Door184 {185 public override void Create()186 {187 Console.WriteLine("创建欧式的房门");188 }189 }190 191 ///192 /// 现代的房顶193 /// 194 public class ModernizationRoof : Roof195 {196 public override void Create()197 {198 Console.WriteLine("创建现代的房顶");199 }200 }201 202 ///203 /// 现代的地板204 /// 205 public class ModernizationFloor : Floor206 {207 public override void Create()208 {209 Console.WriteLine("创建现代的地板");210 }211 }212 213 ///214 /// 现代的窗户215 /// 216 public class ModernizationWindow : Window217 {218 public override void Create()219 {220 Console.WriteLine("创建现代的窗户");221 }222 }223 224 ///225 /// 现代的房门226 /// 227 public class ModernizationDoor : Door228 {229 public override void Create()230 {231 Console.WriteLine("创建现代的房门");232 }233 }
1 ///2 ///先为表弟的房子来建立一个工厂类吧 3 /// 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 ///32 ///古典的房顶33 /// 34 public class ClassicalRoof : Roof35 {36 public override void Create()37 {38 Console.WriteLine("创建古典的房顶");39 }40 }41 42 ///43 /// 古典的地板44 /// 45 public class ClassicalFloor : Floor46 {47 public override void Create()48 {49 Console.WriteLine("创建古典的地板");50 }51 }52 53 ///54 /// 古典的窗户55 /// 56 public class ClassicalWindow : Window57 {58 public override void Create()59 {60 Console.WriteLine("创建古典的窗户");61 }62 }63 64 ///65 /// 古典的房门66 /// 67 public class ClassicalDoor: Door68 {69 public override void Create()70 {71 Console.WriteLine("创建古典的房门");72 }73 }
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 }
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也是具体工厂类
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类型,这个结构很简单,我就不画图了。
五、总结 终于写完了,写了3个小时,学习设计模式不能死学,要把握核心点和使用场景。关键点第一是,面向对象设计模式的基本原则,有了原则,考虑问题就不会跑偏,然后再仔细把握每种模式的使用场景和要解决的问题,多写写代码,多看看Net的类库,它是最好的教材。