
工厂模式有三种,分别是简单工厂模式、工厂方法模式、抽象工厂模式,下面按顺序说一下:
简单工厂模式
概述
简单工厂模式 (Simple Factory Pattern)又叫做静态工厂方法模式(Static Factory Method Pattern),虽然并不属于GoF的23种设计模式之一,但是是学习其他工厂模式的的基础。
定义 :工厂是一个用于创建其他对象的对象 ------ 从形式上讲,工厂是一个函数或方法,它返回不同原型或类型的对象。
结构

主要包含如下几个角色:
- Factory(工厂角色) :即
工厂类,是简单工厂模式的核心,负责实现创建产品实例的内部逻辑,可以被外界调用,根据提供的参数创建所需的对象,提供了静态方法factoryMethod(),返回类型为抽象产品类型Product。 - Product(抽象产品角色) :是工厂类创建的所有对象的
父类,封装了各种产品对象的公有方法,它提高了系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法即可,因为所有的具体产品对象都是其子类 - ConcreteProduct(具体产品角色) :也就是工厂所创建的所有具体对象,每一个具体产品角色都继承了抽象产品角色,例如图中的
ProductOne和ProductTwo,他们都需要实现在抽象角色Product中声明的抽象方法
案例实现
产金币 or 铜币:

核心代码如下:
-
硬币接口类以及具体实现类
javapublic interface Coin { /** * 定义接口,返回硬币描述 * @return */ String getDescription(); }javapublic class GoldCoin implements Coin{ @Override public String getDescription() { return "金币"; } }javapublic class CopperCoin implements Coin{ @Override public String getDescription() { return "铜币"; } } -
工厂类
javapublic class CoinFactory { public static Coin getCoin(int type){ switch (type){ case 1: return new CopperCoin(); case 2: return new GoldCoin(); default: throw new IllegalArgumentException("没有对应的硬币类型"); } } } -
客户端
javapublic class Client { public static void main(String[] args) { /** * ResourceBundle是Java 提供的一个标准工具类,专门用于读取属性文件(.properties)。 * 它会自动在项目的 resources 目录(或者类路径 classpath)下寻找对应的文件 * getBundle("conf"): * 会在你的项目中寻找一个名为 conf.properties 的文件 */ ResourceBundle conf = ResourceBundle.getBundle("conf"); Coin coin = CoinFactory.getCoin(Integer.valueOf(conf.getString("sfp"))); System.out.println("你获得了一枚" + coin.getDescription()); } } -
配置文件:conf.properties
propertiessfp=1
当然其实这个案例也可以简化,将Coin类 与 CoinFactory类 合并成一个接口, 这样可以少一层继承,代码省略,感兴趣可以自己写一写

优缺点以及适用环境
主要优点:
- 工厂类包含了必要的判断逻辑,决定了具体创建哪一个产品实例,客户端不需要直接创建产品对象,仅仅使用即可。实现了对象创建和使用的分离。
- 客户端不需要知道所创建的具体产品类的类名 ,只需要知道所对应的参数即可,这样对于一些复杂的类名,可以减少使用者的记忆量
- 通过引入配置文件 ,可以不修改任何客户端代码的情况下更换具体产品类,提升了系统灵活性
缺点:
- 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受影响。
- 扩展困难,一旦添加新产品就不得不修改工厂类的逻辑,这样会违背开闭原则,例如上面的例子如加一个银币类,那么工厂类里面就需要加上对应的判断代码,而且产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
- 使用简单工厂模式势必会增加系统中类的个数,增加了系统的复杂度和理解难度。
适用场景:
- 工厂类负责创建的对象比较少,这样不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
工厂方法模式
概述
工厂方法模式(Factory Method Pattern) ,继承了简单工厂模式的优点,同时做出了修改以达到符合开闭原则的要求。
工厂方法模式也被称为虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。
定义:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
也就是说,工厂方法模式中不再提供一个工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构
结构

主要包含如下几个角色:
- Product(抽象产品):它是定义产品的接口,是产品对象的公共父类。
- ConcreteProduct(具体产品):实现抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
- Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
- ConcreteFactory(具体工厂):是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。
案例实现

核心代码实现:
-
武器抽象类和具体实现类
javapublic abstract class Weapon { /** * 亮出武器 */ public abstract void showWeapon(); }javapublic class OrcWeapon extends Weapon{ @Override public void showWeapon() { System.out.println("我是兽人,我用的是狼牙棒"); } }javapublic class ElfWeapon extends Weapon { @Override public void showWeapon() { System.out.println("我是精灵,我用弓箭"); } } -
抽象工厂和具体实现类
javapublic interface Blacksmith { /** * 打造装备 * @return 装备 */ Weapon makeWeapon(); }javapublic class OrcBlacksmith implements Blacksmith { @Override public Weapon makeWeapon() { return new OrcWeapon(); } }javapublic class ElfBlacksmith implements Blacksmith { @Override public Weapon makeWeapon() { return new ElfWeapon(); } } -
客户端
javapublic class Client { public static void main(String[] args) throws Exception { //加载配置 ResourceBundle conf = ResourceBundle.getBundle("conf"); String className = conf.getString("fmp"); /** * 反射:创建工厂 * JVM 根据 className 这个字符串去类路径中寻找对应的 .class 字节码文件。 * 在拿到的 Class 对象基础上,调用这个类的无参构造函数创建实例 */ Blacksmith blacksmith = (Blacksmith) (Class.forName(className)).newInstance(); //打造装备 Weapon weapon = blacksmith.makeWeapon(); //显示装备 weapon.showWeapon(); } } -
配置文件
conf.propertiespropertiesfmp=com.zeroone.star.factory.fmp.OrcBlacksmith
优缺点以及适用环境
优点:
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名(只需要知道工厂的类名)。简单工厂模式也有类似的特点
- 基于工厂角色和产品角色的多态性设计 是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
- 添加新产品的时候,只需要添加一个具体工厂和具体产品就可以了,无需修改任何代码,满足开闭原则。系统的可扩展性也就变得非常好。
缺点:
- 在添加新产品时,既需要写新的具体产品类,也还要提供对应的具体工厂类,系统中类的个数将成对增加,一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 由于需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。
适用环境:
- 客户端不知道它所需要的对象的类。
只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。 - 抽象工厂类通过其子类来指定创建哪个对象,利用面向对象的
多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
抽象工厂模式
概述
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,也满足了开闭原则,但是由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,会增加系统的开销。
此时,我们可以考虑将一些相关的产品组成一个"产品族 ",由同一个工厂来统一生产,这就是 抽象工厂模式(Abstract Factory Pattern) 的基本思想。
首先引入两个概念:
- 产品等级结构 :产品等级结构即
产品的继承结构,如一个抽象类是手机,其子类有三星、小米、华为,则抽象手机与具体品牌的手机之间构成了一个产品等级结构,抽象手机是父类,而具体品牌的手机是其子类。 - 产品族 :在抽象工厂模式中,产品族是指
由同一个工厂生产的,位于不同产品等级结构中的一组产品,如小米手机位于手机产品等级结构中、小米笔记本位于笔记本产品等级结构中,小米路由位于路由产品等级结构中,这一系列电子产品就构成了一个产品族。
使用 :当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。
定义:抽象工厂模式提供了一种方法来封装一组具有共同主题的单个工厂,而无需指定其具体类。
结构

主要包含如下几个角色:
- AbstractFactory(抽象工厂) :声明了一组用于创建一组产品 的方法,每一个方法对应一种产品。
- ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
- ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
案例实现

要创建一个王国,我们需要具有共同组织的对象。精灵王国需要一个精灵国王,精灵城堡和精灵军队,而兽人王国需要一个兽人国王,兽人城堡和兽人军队。王国中的对象之间存在依赖关系。
核心代码实现:
-
关于产品的抽象类跟具体实现类
javapublic interface Army { /** * 获取描述 * @return 描述信息 */ String getDescription(); }javapublic class ElfArmy implements Army { @Override public String getDescription() { return "精灵军队"; } }javapublic interface Castle { /** * 获取描述 * @return 描述信息 */ String getDescription(); }javapublic class ElfCastle implements Castle { @Override public String getDescription() { return "精灵城堡"; } }javapublic interface King { /** * 获取描述 * @return 描述信息 */ String getDescription(); }javapublic class ElfKing implements King { @Override public String getDescription() { return "精灵国王"; } } -
关于工厂的抽象类跟具体实现类
javapublic interface KingdomFactory { Castle creatCastle(); King createKing(); Army createArmy(); }javapublic class ElfKingdomFactory implements KingdomFactory { @Override public Castle creatCastle() { return new ElfCastle(); } @Override public King createKing() { return new ElfKing(); } @Override public Army createArmy() { return new ElfArmy(); } }
兽人部落的写法是一样的。这里省略不写了。
-
客户端
javapublic class Client { public static void main(String[] args) throws Exception { //加载配置 ResourceBundle conf = ResourceBundle.getBundle("conf"); String className = conf.getString("afp"); //创建工厂 KingdomFactory factory = (KingdomFactory) Class.forName(className).newInstance(); //创建王国 System.out.println("建造了一座" + factory.creatCastle().getDescription()); System.out.println("推选了一位" + factory.createKing().getDescription()); System.out.println("组建了一支" + factory.createArmy().getDescription()); } } -
配置文件
propertiesafp=com.zeroone.star.factory.afp.impl.ElfKingdomFactory
开闭原则"的倾斜性
在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦 ,抽象工厂模式的这种性质称为 "开闭原则"的倾斜性。
对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
- 增加产品族 :对于增加新的产品族,抽象工厂模式很好地
支持了"开闭原则",只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。 - 增加新的产品等级结构 :对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,
违背了"开闭原则"。
优缺点以及适用环境
优点:
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
- 当一个产品族中的多个对象被设计成一起工作 时,它能够保证客户端始终只使用同一个产品族中的对象。
- 增加新的产品族 很方便,无须修改已有系统,符合"开闭原则"。
缺点:
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了"开闭原则"。
适用环境:
- 用户无须关心对象的创建过程,将对象的创建和使用解耦。其他工厂类也是这样的
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
- 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
总结一下三者
- 如果产品的种类很少,而且几乎不会增加,可以使用简单工厂模式
- 如果同一类产品需要增加很多实现,系统要求有可扩展性,那么可以直接使用工厂方法模式
- 如果存在多个产品等级结构 ,且这些产品必须成套使用 。那么可以直接使用抽象工厂模式
工厂模式还是比较简单的,如果这篇文章对你有帮助,欢迎点赞、评论、关注、收藏。你们的支持是我前进的动力!