设计模式解密(2)- 工厂模式(简单工厂、工厂方法、抽象工厂)
1、前言
工厂模式主要是为创建对象提供接口,将创建对象的过程隔离起来,实现了创建者与调用者的分离,提高了程序的灵活性;
核心本质:
实例化对象,用工厂方法代替new操作;
将选择实现类、创建对象统一管理和控制,从而将调用者跟我们实现类解耦;
工厂模式分类:
简单工厂模式(Simple Factory)(又称:静态工厂方法模式)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory),将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类;
类型:创建型模式
2、简单工厂模式
2-1、介绍
简单工厂模式又被称为静态工厂方法模式;
简单工厂模式是由一个工厂(注意是一个!)对象决定创建出哪一种产品类的实例;
实现方式的实质:由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例;
现实生活中,工厂是负责生产产品的;同样在设计模式中,简单工厂模式我们可以理解为负责生产对象的一个类,称为“工厂类”;
英文:Simple Factory
2-2、解决的问题
将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦;
即使用者可直接消费产品而不需要知道其生产的细节;
2-3、实例引入
背景:这有一个手机生产工厂,能生产多种手机
先定义一个抽象手机类:
package com.designmode.factory.simple; /** * 类说明 :抽象手机类 */ public abstract class Mobile { }
定义具体的手机:小米手机
package com.designmode.factory.simple; /** * 类说明 :具体手机--小米手机 */ public class XiaomiMobile extends Mobile{ }
定义具体的手机:华为手机
package com.designmode.factory.simple; /** * 类说明 :具体手机--华为手机 */ public class HuaweiMobile extends Mobile{ }
最后定义一个工厂:
package com.designmode.factory.simple; /** * 类说明 : */ public class MobileFactory { /** * 静态工厂方法 * @param mobiletype * @return */ public static Mobile product(String mobiletype){ Mobile mobile = null; if ("xiaomi".equals(mobiletype)) { mobile = new XiaomiMobile(); System.out.println("生产小米手机."); } else if ("huawei".equals(mobiletype)) { mobile = new HuaweiMobile(); System.out.println("生产华为手机."); } else { System.out.println("不能生产该手机类型."); } return mobile; } }
下面咱们来生产手机:
package com.designmode.factory.simple; /** * 类说明 :测试 */ public class Test { public static void main(String[] args) { /** * 客户要订购生产小米手机 */ MobileFactory.product("xiaomi"); /** * 客户要订购生产华为手机 */ MobileFactory.product("huawei"); /** * 客户要订购生产锤子手机 */ MobileFactory.product("chuizi"); } }
结果:
生产小米手机. 生产华为手机. 不能生产该手机类型.
2-4、优缺点
优点:
将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,只需要传入工厂需要的参数即可;
把初始化实例时的工作放到工厂里进行,使代码更容易维护;
更符合面向对象的原则 & 面向接口编程;
缺点:
工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂,对于系统维护和扩展不够友好;
简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构;
2-5、应用场景
(1) 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂
(2) 客户端只知道传入工厂类的参数,对于如何创建对象并不关心
(3) 鉴于该模式的缺点,因此一般只在很简单的情况下应用该模式
3、工厂方法模式
3-1、介绍
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象;
抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口;
英文:Factory Method
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类;
3-2、解决的问题
工厂一旦需要生产新产品就需要修改工厂类的方法逻辑,违背了“开放 - 关闭原则“
即简单工厂模式的缺点
之所以可以解决简单工厂的问题,是因为工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则,克服了简单工厂模式中缺点
3-3、实例引入
定义一个抽象手机类
package com.designmode.factory.method; /** * 类说明 :抽象手机类 */ public abstract class Mobile { }
定义一个具体手机类 - 小米手机
package com.designmode.factory.method; /** * 类说明 :具体手机--小米手机 */ public class XiaomiMobile extends Mobile{ }
定义一个具体手机类 - 华为手机
package com.designmode.factory.method; /** * 类说明 :具体手机--华为手机 */ public class HuaweiMobile extends Mobile{ }
定义一个抽象工厂接口
package com.designmode.factory.method; /** * 类说明 :抽象手机生产工厂 */ public abstract interface MobileFactory { public abstract Mobile product(); }
定义具体工厂 - 小米手机生产工厂
package com.designmode.factory.method; /** * 类说明 :具体工厂类 - 小米工厂 */ public class XiaomiFactory implements MobileFactory{ @Override public Mobile product() { System.out.println("生产小米手机."); return new XiaomiMobile(); } }
定义具体工厂 - 华为手机生产工厂
package com.designmode.factory.method; /** * 类说明 :具体工厂类 - 华为工厂 */ public class HuaweiFactory implements MobileFactory{ @Override public Mobile product() { System.out.println("生产华为手机."); return new HuaweiMobile(); } }
下面测试生产小米手机,华为手机
package com.designmode.factory.method; /** * 类说明 :测试 */ public class Test { public static void main(String[] args) { MobileFactory factory = null; factory = new XiaomiFactory(); factory.product(); factory = new HuaweiFactory(); factory.product(); } }
结果:
生产小米手机. 生产华为手机.
3-4、优缺点
优点:
更符合开-闭原则,新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可;
符合单一职责原则,每个具体工厂类只负责创建对应的产品;
总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现;
缺点:
添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度;
虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
一个具体工厂只能创建一种具体产品;
3-5、应用场景
(1) 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;
(2) 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象;
4、抽象工厂模式
4-1、介绍
抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品;
英文:Abstract Factory
定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类;
4-2、解决的问题
每个工厂只能创建一类产品
即工厂方法模式的缺点
4-3、实例引入
创建一个产品抽象族
package com.designmode.factory.absract; /** * 类说明 :抽象产品族 */ public abstract class AbstractProduct { }
创建一个手机抽象类
package com.designmode.factory.absract; /** * 类说明 :抽象手机类 */ public abstract class Mobile extends AbstractProduct{ }
创建一个MP3抽象类
package com.designmode.factory.absract; /** * 类说明 :抽象MP3类 */ public abstract class MP3 extends AbstractProduct{ }
创建一个具体手机类 - 小米手机
package com.designmode.factory.absract; /** * 类说明 :具体手机--小米手机 */ public class XiaomiMobile extends Mobile{ }
创建一个具体手机类 - 华为手机
package com.designmode.factory.absract; /** * 类说明 :具体手机--华为手机 */ public class HuaweiMobile extends Mobile{ }
创建一个具体MP3类 - 小米MP3
package com.designmode.factory.absract; /** * 类说明 :具体MP3--小米MP3 */ public class XiaomiMP3 extends MP3{ }
创建一个具体MP3类 - 华为MP3
package com.designmode.factory.absract; /** * 类说明 :具体MP3--华为MP3 */ public class HuaweiMP3 extends MP3{ }
创建抽象工厂类
package com.designmode.factory.absract; /** * 类说明 :抽象工厂类 */ public abstract interface AbstractFactory { public abstract Mobile productMobile(); public abstract MP3 productMP3(); }
创建具体工厂类 - 小米工厂
package com.designmode.factory.absract; /** * 类说明 :小米工厂类 */ public class XiaomiFactory implements AbstractFactory{ @Override public Mobile productMobile() { System.out.println("生产小米手机."); return new XiaomiMobile(); } @Override public MP3 productMP3() { System.out.println("生产小米MP3."); return new XiaomiMP3(); } }
创建具体工厂类 - 华为工厂
package com.designmode.factory.absract; /** * 类说明 :华为工厂类 */ public class HuaweiFactory implements AbstractFactory{ @Override public Mobile productMobile() { System.out.println("生产华为手机."); return new HuaweiMobile(); } @Override public MP3 productMP3() { System.out.println("生产华为MP3."); return new HuaweiMP3(); } }
下面测试一下:生产 小米手机、MP3;华为手机、MP3
package com.designmode.factory.absract; /** * 类说明 :测试 */ public class Test { public static void main(String[] args) { AbstractFactory factory = null; factory = new XiaomiFactory(); factory.productMobile(); factory.productMP3(); factory = new HuaweiFactory(); factory.productMobile(); factory.productMP3(); } }
结果:
生产小米手机. 生产小米MP3. 生产华为手机. 生产华为MP3.
4-4、优缺点
优点:
1)分离接口和实现
客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦;
2)使切换产品族变得容易
因为一个具体的工厂实现代表的是一个产品族,拿上面的代码来说,就是从“小米”到“华为”只需要切换一下具体的工厂即可;
缺点:
1)不太容易扩展新的产品
如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类;
3-5、应用场景
为创建一组对象提供了一种解决方案;
5、总结
简单工厂模式:
简单工厂类负责了所有产品的创建逻辑,当我们需要新引进一个新产品时,就不得不修改工厂类的产品创建逻辑,在产品类型较多时有可能会造成工厂类的产品创建逻辑过于负责,不利于系统的维护性和扩展性;
工厂方法模式:
对简单工厂模式的设计优化,简单工厂模式中如果新增一类产品类型时,需要修改工厂静态方法的产品创建逻辑,而使用工厂方法模式只需新扩展出一个新的工厂子类或是实现类来针对新增类型产品的创建工作、使系统具有了良好的扩展性与维护性;
抽象工厂模式:
为创建一组对象提供了一种解决方案,与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品;
PS:源码地址 https://github.com/JsonShare/DesignPattern/tree/master
PS:原文地址 http://www.cnblogs.com/JsonShare/p/7098376.html