前言:仅当复习讨论,写得不好,多多指教!
抽象工厂模式
UML
又经过三年之后,中国已经越来越国际化了,很多日本人来中国留学也带来了本土的猫和狗。一旦他们留学回去之后,就把这些动物送到了动物流浪工厂中。此时,个别对小日本有抵触的人并不想为这些日本的动物喂食,于是拉起一部分人到工厂去抗议,要求自己的食物只给中国的动物吃,把日本的动物赶出去。厂长一看这么多人抗议,没办法,只能把动物分国籍了,于是把中国流浪动物在一个工厂,日本流浪动物在另外一个工厂。
某一天,一位本来认为日本的动物也是动物的爱心人士看到了安培晋三参拜靖国神社的新闻,于是她要求原来喂养的日本流浪动物 切换 到中国流浪动物,如下图所示,她只要切换一个工厂就可以达成心愿。
对比一下业务场景
概念
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。(如上图,提供了数据库抽象工厂,而无需指定具体数据库给客户端)
优点
- 最大的好处就是易于交换产品体系(sqlserver 替换成 oracle),由于具体工厂类,例如sql server工厂在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的配置。
- 它让具体的创建实例过程与客户端分离,客户单是通过它们的抽象接口操作实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中(比如sqlserverUser, 客户端只知道抽象类,不关心你是用sql server还是用oracle来实现。全部都依赖抽象,符合依赖倒置原则)
缺点
- 如果更换 产品体系,改动的工作量非常大,因为到处都有 IFactory factory=new SqlserverFactory()的实现。这么实例化1000次,就要改1000次。
- 增加一个功能,要涉及到增加三个类和修改三个工厂,这。。。比较累人。
改进
针对以上两个问题,来进行解决。1.可不可动态实例化?2. 增加类是可扩展的,但是修改三个工厂是否可以去掉?
答案是:可以的,利用反射+配置文件
UML
我们将工厂干掉,利用数据库Context类来动态实例化具体的功能类(产品类)。利用反射来实例化相关的实例,而不是让工厂去实例化,实例化格式如下:
Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名称”)
数据库Context代码如下:
class 数据库Context
{
private static readonly string db=ConfigurationManager.Appsettings["DB"];
private static readonly string AssemblyName="程序集名称";
public static IUser 增加用户()
{
string className=AssemblyName+".User";
return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
}
//其他类似
}
总结
介绍完了抽象工厂模,但是它跟工厂方法的差异在哪里?
- 每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。
- 工厂方法模式是一定要利用工厂抽象类的,这个是包含在它的定义中的。而抽象工厂模式进阶中已经干掉了抽象工厂类,去利用反射进行实例化。
如果新增一个产品类,数据库Context类里是需要增加一个实例化子类的方法的。 这个违背开放-封闭原则吗?