首先明确什么是工厂模式:
(1)可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,只需依赖工厂即可得到自己想要的产品。
(2)对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
(3)降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的。
而且,工厂模式可以分为简单工厂模式、工厂方法模式、抽象工厂模式。下面是对这三种工厂模式的对比和分析。
【简单工厂模式】
1.概念:从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GDF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。简单的说,简单工厂模式更多的使用了面向对象编程中的多态性,基类的引用可以指向派生类,并且调用派生的方法,即多态性。
2.如图所示:
3.个人理解:
简单工厂模式基本原理就是创建一个抽象,然后该抽象决定要返回的可能的几个类是哪些,接着简单工厂返回其中之一,然后就可以在无需知道真正使用的哪个子类的情况下调用返回的类实例的方法,这一做法把数据依赖问题与类的使用方法隔离开来。
举个例子来说:
简单工厂返回有着相同方法的类实例,他们有可能是不同的派生类的实例,或者有可能实际上是互不相关的类,只是共有相同的接口而已。无论是哪种方式,这些类实例的方法都是相同的,可以互换使用。
但是,超模大赛上简单工厂模式之所以没有入选是因为它符合开放-封闭原则的精髓,它在对每一次扩展时都要更改工厂类,这就是对修改开放了,当然就不符合开闭原则喽。
【工厂方法模式】
1.概念:工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
2.如图所示:
通过工厂方法模式的类图可以看到,工厂方法模式有四个要素
(1)工厂接口。工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。
(2)工厂实现。在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。
(3)产品接口。产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。
(4)产品实现。实现产品接口的具体类,决定了产品在客户端中的具体行为。
3.个人理解:
其实,工厂方法模式就是在简单工厂模式的基础之上又抽象出来了一个对象类。还是先看一下刚才那个例子:
这样一来,就弥补了超模大赛上简单工厂的缺陷。所以说,使用工厂方法后,调用端的耦合度大大降低了。并且对于工厂来说,是可以扩展的,以后如果想组装其他的汽车,只需要再增加一个工厂类的实现就可以。无论是灵活性还是稳定性都得到了极大的提高。
下面具体说一下工厂方法模式的适用场合:
(1)作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
(2)工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
(3)由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。
4.简单工厂VS工厂方法
说了这么多,想必无需再多言,二者区别就显而易见啦
(1)简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
(2)工厂方法实现是,客户端需要决定实例化哪一个工厂来实现ConcreteProduct类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你想要加功能,本来是该工厂类,而现在是修改客户端类。
【抽象工厂模式】
1.概念:抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。
2.如图所示:
3.个人理解:
在我看来,抽象工厂模式跟工厂方法模式一个是针对于解决多个问题,一个是针对于解决一个问题。但是它们所体现的实现是一致的,只不过是范围的不同。还是最前面动物的那个例子,这次是给动物类新添加了一个跑的功能,当然,加菲猫和哈巴狗都可以继承这个跑的功能。只是这次抽象出来两个类,在客户端处就不存在实际类之间的相互联系,只是抽象类之间的作用关系,这样也是减弱耦合性,提高代码的复用性,符合开放-封闭原则及依赖倒转原则。
【三姐妹关联】
但是,并非说抽象工厂模式就是最好的模式,用简单工厂改进抽象工厂:再多个抽象类的基础上再抽象出一个类来,这样就不至于在功能扩展时再去添加那么多的类了,这个时候再用Switch语句进行选择一下就好啦,真正达到了解耦的效果。
这还不算是完美,在学习策略模式的时候最后面还提了一句“反射反射,程序员的快乐”只是在众多文字中多看了它一眼,所以带着极大的好奇心接着往后学,不晓得到底它是有多么的神奇。终于学到抽象工厂模式的时候,遇到了它,有种似曾相识的愉悦感,有了它,我们就可以和Switch说再见啦,那么什么是反射呢?
反射:作为一种编程方式,可以理解为是一种依赖注入。它的格式是:
Assembly.Load("程序集名称").CreateInstance("命名空间.类名称")
看下面一个对比:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><strong><span style="font-family:KaiTi_GB2312;font-size:18px;"><strong>//常规的写法 IUser result=new SqlserverUser();</strong></span></strong></span>
<span style="font-family:KaiTi_GB2312;font-size:18px;"><strong><span style="font-family:KaiTi_GB2312;font-size:18px;"><strong>//反射的写法 using Syetem.Reflection; IUser result=(IUser)Assembly.Load("抽象工厂模式").CreateInstance("抽象工厂模式.SqlserverUser");</strong></span></strong></span>
显然,后面用到反射的这种方法,更方便灵活,如果出现新的需求,修改的成本会比较小。
总结:经过了如此一番分析和对比,工厂三姐妹就这么被我看透了,呵呵。。。当然这个还是初次学习,会有理解不到位的地方,在以后的学习中慢慢体会,慢慢改变...突然觉得自己喜欢上了大鸟和小菜喜欢上了设计模式,继续努力啦。。。
来源:https://www.cnblogs.com/fengkungui/p/6040216.html