从部分博客摘录过来
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
个人理解:顾名思义工厂模式就是按照工厂流水线的模式去生成产品,其设计思想就是提取产品的共性去制造流水线(接口包含的方法),之后创建一个工厂(工厂类)去包装这个流水线,最后通过工厂去制造具有这些共性的不同产品(产品实现接口,重写接口方法)。这就是工厂模式。
工厂方法模式是创建型模式,工厂模式根据抽象程度可以分为三种:简单工厂模式,工厂方法模式,抽象工厂模式。
一、简单工厂模式
定义:简单工厂模式又叫做静态工厂方法模式。一个抽象产品类,可以派生出多个具体产品类。一个具体工厂类,通过往此工厂的static方法中传入不同参数,产出不同的具体产品类实例。
概括:Concrete Product 具有共同的父类Product。工厂类Factory只有一个,没有子父类,通过向Factory的static方法中传入不同的参数,得到返回的不同的Concrete Product。
一般的流程是:规范接口—>实现类—>工厂创建
UML:
角色说明:
- Product(抽象产品类):要创建的复杂对象,定义对象的公共接口。
- ConcreteProduct(具体产品类):实现Product接口。
- Factory(工厂类):返回ConcreteProduct实例。
实例说明:举个生活中的例子:比如批量生产汽车:(产品)汽车都包含车架、轮子、座椅等共性(接口包含的方法),但是生产一个车架、轮子、座椅就组装一辆汽车,太麻烦太没效率了。于是就建造了一个工厂(工厂类)①并添加了很多生产车架、轮子、座椅的流水线(汽车共性的接口)②,如果要生产汽车就要先和工厂签合同(产品实现接口)③,然后去流水线生产车架、轮子、座椅等(开始生产产品)④。
代码体现:
①
/** * 生产汽车的工厂 */ private class MakeCarFactory { public static CarInterface createCar(String carName){ CarInterface carInterface= null ; switch (carName){ case "A" : carInterface= new CarA(); break ; case "B" : carInterface= new CarB(); break ; default : } return carInterface; } } |
②
/** * 将汽车共性抽成接口 */ public interface CarInterface{ void makeCheJia(); //制造车架 void makeLunZi(); //制造轮子 void makeZuoYi(); //制造座椅 } |
③
/** * 汽车A实现接口 */ public class CarA implements CarInterface{ @Override public void makeCheJia() { LogUtil.d( "制造出汽车A的车架" ); } @Override public void makeLunZi() { LogUtil.d( "制造出汽车A的轮子" ); } @Override public void makeZuoYi() { LogUtil.d( "制造出汽车A的座椅" ); } } /** * 汽车B实现接口 */ public class BenZ implements CarInterface{ @Override public void makeCheJia() { LogUtil.d( "制造出汽车B的车架" ); } @Override public void makeLunZi() { LogUtil.d( "制造出汽车B的轮子" ); } @Override public void makeZuoYi() { LogUtil.d( "制造出汽车B的座椅" ); } } |
④
/** * @author tzt * @date 2020/11/19 */ public class FactoryDemoActivity extends Activity { @Override protected void onCreate( @Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); makeCarA(); makeCarB(); } /** * 开始制造汽车A */ private void makeCarA() { CarInterface carA = MakeCarFactory.createCar( "A" ); //重写接口方法 carA.makeCheJia(); carA.makeLunZi(); carA.makezuoYi(); } /** * 开始制造汽车B */ private void makeCarB() { CarInterface carB = MakeCarFactory.createCar( "B" ); //重写接口方法 carB.makeCheJia(); carB.makeLunZi(); carB.makezuoYi(); } } |
优点:
1.将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,实现了解耦;
2.把初始化实例时的工作放到工厂里进行,使代码更容易维护。 更符合面向对象的原则 & 面向接口编程,而不是面向实现编程。
缺点:
1.工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
2.违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。
3.简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构
优化:由于简单工厂模式新增产品时需要直接修改工厂类,违反了开放封闭原则。因此可以使用反射来创建实例对象,确保能够遵循开放封闭原则。
使用反射来实现工厂类,新增产品时无需修改工厂类,但是使用反射来创建实例对象的话会比正常使用new来创建的要慢。
/** *优化:通过反射的行为拿到实例 * 但是需要把CarInterface接口改为抽象类 */ public static extends Product> T create(Class clz) {
Product product = null ; try { product = (Product) Class.forName(clz.getName()).newInstance(); //反射出实例 } catch (Exception e) { e.printStackTrace(); } return (T) product; } |
二、工厂方法模式
定义:工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
概括:Concrete Product 具有共同的父类Product ,Concrete Factory也具有共同的父类Factory。每个具体的子类Concrete Factory 产出一个对应的Concrete Product。
总结:一个抽象产品类,可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例。
UML:
实例说明:比如宝马、奔驰、奥迪等汽车(产品)都包含车架、轮子、座椅等共性(接口包含的方法)。如果各家汽车都自己去生产太麻烦了,然后就一起建造了一个大的工厂(工厂抽象基类)⑤,然后大工厂下面又为每家品牌商建造了属于他们自己的小工厂(工厂具体类)⑥,用于批量生产车架、轮子、座椅(汽车共性的接口)②,宝马要生产宝马车,先去和工厂签合同(产品实现接口)⑦,然后去流水线生产带有宝马标记的车架、轮子、座椅等(开始生产产品)⑧。
代码体现:
⑤
/** * @author tzt * @date 2020/11/24 * 创建用户生产汽车的工厂的基类 */ public abstract class CarFactory { /** * 提取子工厂类的共性 * @return CarInterface 汽车共性的接口 */ public abstract CarInterface createCar(); } |
⑥
/** * 生产宝马汽车的工厂类 */ public class BMWCarFactory extends CarFactory { @Override public CarInterface createCar() { return new BMWCar(); } } /** * 生产奔驰汽车的工厂类 */ public class BenZCarFactory extends CarFactory { @Override public CarInterface createCar() { return new BenZ(); } } |
⑦
/** * 宝马车实现接口 */ public class BMWCar implements CarInterface{ @Override public void makeCheJia() { LogUtil.d( "制造出带宝马标记的车架" ); } @Override public void makeLunZi() { LogUtil.d( "制造出带宝马标记的轮子" ); } @Override public void makeZuoYi() { LogUtil.d( "制造出带宝马标记的座椅" ); } } /** * 奔驰车实现接口 */ public class BenZ implements CarInterface{ @Override public void makeCheJia() { LogUtil.d( "制造出带奔驰标记的车架" ); } @Override public void makeLunZi() { LogUtil.d( "制造出带奔驰标记的轮子" ); } @Override public void makeZuoYi() { LogUtil.d( "制造出带奔驰标记的座椅" ); } } |
⑧
/** * @author tzt * @date 2020/11/19 * 开始生产汽车 */ public class FactoryDemoActivity extends Activity { @Override protected void onCreate( @Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); makeBMW(); makeBenZ(); } /** * 开始制造宝马汽车 */ private void makeBMW() { CarInterface bmwCar = new BMWCarFactory().createCar(); bmwCar.makeCheJia(); bmwCar.makeLunZi(); bmwCar.makezuoYi(); } /** * 开始制造奔驰车 */ private void makeBenZ() { CarInterface benZCar = new BenZCarFactory().createCar(); benZCar.makeCheJia(); benZCar.makeLunZi(); benZCar.makezuoYi(); }} |
优点:
1、更符合开-闭原则
新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可,而简单工厂模式需要修改工厂类的判断逻辑
2、符合单一职责原则
每个具体工厂类只负责创建对应的产品,而简单工厂中的工厂类存在复杂的switch逻辑判断
3、不使用静态工厂方法,可以形成基于继承的等级结构,而简单工厂模式的工厂类使用静态工厂方法
优点总结:工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
缺点:
1、添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
2、由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
3、虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
4、一个具体工厂只能创建一种具体产品
三、抽象工厂模式
定义:抽象工厂模式,即Abstract Factory Pattern,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类;具体的工厂负责实现具体的产品实例。
概括:抽象工厂模式引入抽象产品族Abstract Product 的概念,它是所有产品的父类,其下是Product抽象类,它是Abstract Product的子类,是具体产品类的父类,可有多种不同类型,如ProductA 、Product B,再往下,是具体的产品类 Concrete ProductA 、Concrete ProductB;
Concrete Factory 有共同的父类Abstract Factory。每个具体的Concrete Factory都可以生产多种不同产品。如Factory 1 可以生产Concrete ProductA1、Concrete Product B1,Factory 2可以生产Concrete A2、Concrete B2。
总结:多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。 每个具体工厂类可以创建多个具体产品类的实例。
UML:
实例说明:还以上面的生产宝马、奔驰汽车为例。汽车都有发动机、轮胎等共性(抽象产品类)⑼;但是轮胎又分为米其林轮胎、邓禄普牌轮胎等,发动机又分为宝马发动机、奔驰发动机(具体产品类)⑽;要生产汽车,首先先创建一个大的总工厂用于生产各种类的轮胎、发动机等汽车配件(抽象工厂类)⑾;之后如果要生产宝马汽车,需要在总工厂下创建一个专门生产米其林轮胎、宝马发动机的宝马工厂(具体工厂类)⑿;最后宝马商需要和宝马工厂签订合同开始生产宝马汽车(开始生产产品)⒀。
知识点补充:查询资料可知宝马汽车使用的是米其林轮胎和自主研发的宝马发动机、奔驰汽车使用的是邓禄普牌轮胎和自主研发的奔驰发动机。 |
代码示例:
⑼
/** * 抽象产品类----轮胎 */ public abstract class Tyre { public abstract void makeTyre(); } /** * 抽象产品类----发动机 */ public abstract class Engine { public abstract void makeEngine(); } |
⑽
/** *具体产品类-----米其林轮胎 */ public class MichelinTyre extends Tyre { @Override public void makeTyre() { LogUtil.d( "制造出米其林轮胎" ); } } /** * 具体产品类-----邓禄普牌轮胎 */ public class DunlopTyre extends Tyre { @Override public void makeTyre() { LogUtil.d( "制造出邓禄普牌轮胎" ); } } /** * 具体产品类-----宝马发动机 */ public class BMWEngine extends Engine { @Override public void makeEngine() { LogUtil.d( "制造出宝马发动机" ); } } /** * 具体产品类-----奔驰发动机 */ public class BenzEngine extends Engine { @Override public void makeEngine() { LogUtil.d( "制造出奔驰发动机" ); } } |
⑾
/** * @author tzt * @date 2020/11/24 * 抽象工厂类-----汽车工厂类 */ public abstract class CarFactory { public abstract Tyre createTyre(); public abstract Engine createEngine(); } |
⑿
/** * @author tzt * @date 2020/11/24 * 具体工厂类------宝马汽车厂 */ public class BMWCarFactory extends CarFactory { @Override public Tyre createTyre() { //宝马汽车用的是米其林轮胎 return new MichelinTyre(); } @Override public Engine createEngine() { //宝马汽车用的自主研发的宝马发动机 return new BMWEngine(); } } /** * @author tzt * @date 2020/11/24 * 具体工厂类------奔驰汽车厂 */ public class BenzCarFactory extends CarFactory { @Override public Tyre createTyre() { //奔驰汽车用的是禄普牌轮胎 return new DunlopTyre(); } @Override public Engine createEngine() { //奔驰汽车用的自主研发的奔驰发动机 return new BenzEngine(); } } |
⒀
/** * @author tzt * @date 2020/11/19 * 开始生产汽车 */ public class FactoryDemoActivity extends Activity { @Override protected void onCreate( @Nullable Bundle savedInstanceState) { super .onCreate(savedInstanceState); makeBMW(); makeBenZ(); } /** * 开始制造宝马汽车 */ private void makeBMW() { //创建宝马工厂 CarFactory bmwCarFactory = new BMWCarFactory(); //创建宝马专用发动机 Engine engine = bmwCarFactory.createEngine(); //开始生产发动机 engine.makeEngine(); //创建宝马装用轮胎--米其林轮胎 Tyre tyre = bmwCarFactory.createTyre(); //开始生产轮胎 tyre.makeTyre(); } /** * 开始制造奔驰车 */ private void makeBenZ() { //创建奔驰工厂 CarFactory benzCarFactory = new BenzCarFactory(); //创建奔驰专用发动机 Engine engine = benzCarFactory.createEngine(); //开始生产发动机 engine.makeEngine(); //创建奔驰专用轮胎-----邓禄普牌轮胎 Tyre tyre = benzCarFactory.createTyre(); //开始生产轮胎 tyre.makeTyre(); } } |
优点:
1、降低耦合
抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展;
2、更符合开-闭原则
新增一种产品类时,只需要增加相应的具体产品类和相应的工厂子类即可,而简单工厂模式需要修改工厂类的判断逻辑
3、符合单一职责原则
4、每个具体工厂类只负责创建对应的产品,而简单工厂中的工厂类存在复杂的switch逻辑判断
5、不使用静态工厂方法,可以形成基于继承的等级结构,而简单工厂模式的工厂类使用静态工厂方法
缺点:
抽象工厂模式很难支持新种类产品的变化。
这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类的以及所有子类的改变,这样也就违背了“开发——封闭”原则。
工厂方法模式与抽象工厂模式比较
- 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性。
- 抽象工厂模式则可以提供多个产品对象,而不是单一的产品对象
总结:
简单工厂模式:一个抽象产品类,可以派生出多个具体产品类。一个具体工厂类,通过往此工厂的static方法中传入不同参数,产出不同的具体产品类实例。
工厂方法模式:一个抽象产品类,可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式: 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。 每个具体工厂类可以创建多个具体产品类的实例。
优点:从上面的例子可以很明显的看出其优点:批量生产的每一个产品不需要自己单独处理复杂的制造逻辑,只需要通过工厂类去无脑的走完生产流程即可。工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定 的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而 不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。
缺点:由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则⑤,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;
⑤高内聚责任分配原则:内聚是评价一个元素的职责被关联和关注强弱的尺度。如果一个元素具有很多紧密相关的职责,而且只完成有限的功能,则这个元素就具有高内聚性。此处的元素可以是类,也可以是模块、子系统或者系统。在一个低内聚的类中会执行很多互不相关的操作,这将导致系统难于理解、难于重用、难于维护、过于脆弱,容易受到变化带来的影响。