一. 引言
1. 定义
在Java一般通过new操作符产生一个对象实例,new操作符就是用来构造对象实例的。
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
工厂模式负责将大量共同接口的类实例化,工厂模式可以决定将哪一个类实例化,不必事先知道每次要实例化哪个类
虽然使用工厂模式,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量,提高系统稳定性降低耦合。
所以在一些书籍中工厂模式这样定义:工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
2. 工厂模式的分类(三类)
1)简单工厂模式(Simple Factory)
2)工厂方法模式(Factory Method)
3)抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。
GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。
将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
二 . 简单工厂模式
1. 定义
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。
在简单工厂模式中,可以根据自变量的不同返回不同类的实例。
简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
2. 组成部分以及优缺点
先来看简单工厂模式的一个例子:
- //抽象产品角色
- public interface Car{
- public void infomation();
- }
- //具体产品角色
- public class Benz implements Car{
- public void Infomation() {
- System.out.println("奔驰车 Made In China");
- }
- }
- public class Bmw implements Car{
- public void Infomation() {
- System.out.println("宝马车 Made In China");
- }
- }
- //工厂类角色
- public class Factory{
- //工厂方法.注意 返回类型为抽象产品角色
- public static Car createCar(String type)throws Exception{
- Car c = null;
- try{
- c = (Car)class.forName(type).newInstance();
- } catch(Exception e){
- e.printStackTrace();
- }
- return c;
- }
- }
然后客户类使用:
public class Customer{public static void main(String[] args) {Car car= Factory.createCar(benz); // 根据传入的类字节码字符串得到通用接口car.Infomation(); // 多态性体现,输出"奔驰车 Made In China"}}
① 通过上面的例子可以发现简单工厂模式由三部分组成:
1) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
2) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。
3) 工厂类角色:这是本模式的核心,被客户端直接调用,根据客户端指定传入的参数,动态创建客户端需要的对象
② 步骤:
1. 抽象出通用接口,这里是Car接口
2. 对象实现通用接口,这里是benz和Bmw 实现Car接口
3. 创建静态工厂,通过特定参数组,得到通用接口对象
4. 已经得到了通用接口对象,就可以调用具体类类完成同一种功能的同名方法
可以看出,客户端只面对工厂,不用管产品的具体细节,客户只需向工厂要求你需要什么,其他的事情都交给工厂了。
③ 简单工厂模式的优缺点
优点:
1)工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单
工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
2)客户端无需知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者
的记忆量。
3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
1) 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
2) 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
③ 适用环境
1)工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂
2)客户端只知道传入工厂类的参数,对于如何创建对象不关心
3. 出现的问题
下面我们从开闭原则(对扩展开放;对修改封闭)上来分析下简单工厂模式。当客户不再满足现有的车型号的时候,想要另一种新型车,只要这种车符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。所以对产品部分来说,它是符合开闭原则的;但是工厂部分好像不太理想,因为每增加一种新型车,都要在工厂类中增加相应的创建业务逻辑(createCar(String type)方法需要新增case),这显然是违背开闭原则的。可想而知对于新产品的加入,工厂类是很被动的。对于这样的工厂类,我们称它为全能类或者上帝类。
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝累坏了,也累坏了我们这些程序员。
于是工厂方法模式作为救世主出现了。 工厂类定义成了接口,而每新增的车种类型,就增加该车种类型对应工厂类的实现,这样工厂的设计就可以扩展了,而不必去修改原来的代码。
三. 工厂方法模式
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力
可以由工厂方法模式里不同的工厂子类来分担。
1. 组成部分
由于增加了子工厂分担压力,所以工厂方法模式的组成部分变成了四个部分:
1) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
2) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。
3) 抽象工厂类角色,这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
4) 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
2. 例子分析
- //抽象产品角色
- public interface Car{
- public void create();
- }
- //具体产品角色
- public class Benz implements Car{
- public void Infomation() {
- System.out.println("奔驰车 Made In China");
- }
- }
- public class Bmw implements Car{
- public void Infomation() {
- System.out.println("宝马车 Made In China");
- }
- }
- //抽象工厂类角色
- public abstact class Factory{
- public Car CreateCar();
- }
- ‘
- //具体工厂角色
- public class FactoryBenz extends Factory{
- //Override
- public static benz createCar() {
- return new Benz();
- }
- }
客户类只需要关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名:
public class Customer{public static void main(String[] args) {Factory FactoryBenz = new FactoryBenz();FactoryBenz.createCar()Benz benz = factorybenz.createCar(); // 生产出了一个奔驰车}}
3. 具体分析
工厂方法被定义为:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
在工厂方法模式中,抽象产品类Product负责定义产品的共性,实现对事物最抽象定义;Creator为抽象创建类,也就是抽象工厂,
具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的
4. 优缺点
优点:
① 良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,
只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,减少模块间的耦合。
② 工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化”。
例如在我们的例子中,需要增加一个大众汽车,则只需要增加一个具体大众汽车类,工厂类不用任何修改就可完成系统扩展。
如果需要增加 衣服制造,就只要多增加一个衣服知道的具体工厂类来分担
四. 抽象工厂模式
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。
比如奔驰系列使用空调型号A和发动机型号A,而宝马系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,
在为汽车生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号。
解析:
当每个抽象产品都有多于一个的具体子类的时候(空调有型号A和B两种,发动机也有型号A和B两种),工厂角色怎么知道实例化哪一个子类呢?
比如每个抽象产品角色都有两个具体产品(产品空调有两个具体产品空调A和空调B)。抽象工厂模式提供两个具体工厂角色(宝马系列工厂和奔驰系列工
厂),分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。
每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例
② 例子
- //发动机以及型号
- public interface Engine {
- }
- public class EngineA extends Engine{
- public EngineA(){
- System.out.println("制造-->EngineA");
- }
- }
- public class EngineBextends Engine{
- public EngineB(){
- System.out.println("制造-->EngineB");
- }
- }
- //空调以及型号
- public interface Aircondition {
- }
- public class AirconditionA extends Aircondition{
- public AirconditionA(){
- System.out.println("制造-->AirconditionA");
- }
- }
- public class AirconditionB extends Aircondition{
- public AirconditionB(){
- System.out.println("制造-->AirconditionB");
- }
- }
创建工厂类:
- //创建工厂的接口
- public interface AbstractFactory {
- //制造发动机
- public Engine createEngine();
- //制造空调
- public Aircondition createAircondition();
- }
- //为奔驰系列生产配件
- public class FactoryBenz implements AbstractFactory{
- @Override
- public Engine createEngine() {
- return new EngineA();
- }
- @Override
- public Aircondition createAircondition() {
- return new AirconditionA();
- }
- }
- }