💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ## 1. 工厂模式 ### 1. 工厂模式说明 #### 1.1 什么是工厂模式 工厂模式的作用是屏蔽创建对象过程中的具体过程,以便提高创建对象过程的灵活性,使使用者不必关心构造对象的细节和复杂的过程。 #### 1.2 什么时候使用 **1. 如果一个对象拥有很多子类**,那么创建该对象的子类使用工厂模式是最合适的,不但可以面向接口的编程,为维护以及开发带来方便。 **2. 如果创建某个对象时需要进行许多额外的操作**,如查询数据库然后将查询到的值赋予要创建的对象(单例初始化时使用比较多),或是需要许多额外的赋值等等。如果查看JDK源码中,会发现许多成员变量在对象构造时,通过工厂方法进行创建的。因为这些成员变量本身的创建也很复杂。不可能创建对象时,在该对象的构造方法里创建成员变量然后再赋值给该成员变量。而且使用工厂模式也提高了代码的重用性。 > 面向对象的编程的思想是分派和封装,即为将复杂的代码分派成多个代码块,然后对这些代码块进行封装,这样如果需要修改只修改每段即可,而不会牵一发而动全身,小功能解耦。 #### 1.3 工厂模式中的角色 在工厂模式中一般存在以下三个类型的角色,分别是: 1. **产品类** :最终产出的产品 2. **工厂类**:就是生产产品的工厂 3. **客户类**: 是最终产品的需求者。 ### 2. 工厂模式实现方式 #### 2.1 单工厂模式(Simple Factory) 简单工厂模式对上面提到的工厂模式中三个类型角色中的产品类进行了修改, **把产品类进行了抽象,分成了抽象产品角色和具体产品角色,其他角色类不变。** 抽象产品角色一般是具体产品类需要继承的父类或者需要实现的接口,而具体产品角色就是工厂类中需要创建的产品实例。 > 1. 定义产品类接口 > 2. 具体的产品类实现产品接口 > 3. 工厂类根据传入的不同的值,返回不同的产品类对象 > 4. 不修改代码的话,是无法扩展的。 1. 产品类 ![](https://box.kancloud.cn/a95541cd84cdb93fbaa09da425fa043f_473x274.png) 2. 工厂类 ![](https://box.kancloud.cn/9d6590fdde8f92c929d09157cd6c8e22_376x276.png) 3. 客户类 ![](https://box.kancloud.cn/0001bb84e536a00d1d257bb2f2e734d2_482x118.png) #### 2.2 工厂方法模式(Factory Method) 工厂方法模式对上面提到的简单工厂模式又进行了一部分修改,在简单工厂模式的基础上把工厂类进行了抽象,**分成了抽象工厂角色和具体工厂角色。** 抽象工厂角色是工厂方法模式中的核心部分,是必须由具体工厂角色进行继承或者实现的父类或者接口。具体工厂角色在继承或者实现抽象工厂角色后在自己的内部做具体的业务逻辑。 > 1. 在单工厂模式的基础上 > 2. 为不同的产品类,创建不同的工厂类(相同的工厂接口和方法) > 3. 在同一等级结构中, 支持增加任意产品 。 1. 产品类 ![](https://box.kancloud.cn/a95541cd84cdb93fbaa09da425fa043f_473x274.png) 2. 工厂类 ![](https://box.kancloud.cn/a8d2f545c8140d56a79f91309e4bc63e_531x339.png) 3. 客户类 ![](https://box.kancloud.cn/cf05a13991a9cc226ec21d0be1a22bd5_449x147.png) #### 2.3 抽象工厂模式(Abstract Factory) 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。 在上述的场景上继续延伸:咖啡工厂做大做强,引入了新的饮品种类:茶、 碳酸饮料。中国工厂只能制造咖啡和茶,美国工厂只能制造咖啡和碳酸饮料。 如果用上述工厂方法方式,除去对应的产品实体类还需要新增2个抽象工厂(茶制造工厂、碳酸饮料制造工厂),4个具体工厂实现。随着产品的增多,会导致类爆炸。 所以这里引出一个概念**产品家族**,在此例子中,不同的饮品就组成我们的饮品家族, 饮品家族开始承担创建者的责任,负责制造不同的产品。 **和工厂方法的区别是,抽象工厂往往有多种方法,可以生产多种产品,即产品簇。 ** ~~~ /** * 抽象的饮料产品家族制造工厂 * */ public interface AbstractDrinksFactory { /** * 制造咖啡 * @return */ Coffee createCoffee(); /** * 制造茶 * @return */ Tea createTea(); /** * 制造碳酸饮料 * @return */ Sodas createSodas(); } /** * 中国饮品工厂 * 制造咖啡与茶 * */ public class ChinaDrinksFactory implements AbstractDrinksFactory { @Override public Coffee createCoffee() { // TODO Auto-generated method stub return new Latte(); } @Override public Tea createTea() { // TODO Auto-generated method stub return new MilkTea(); } @Override public Sodas createSodas() { // TODO Auto-generated method stub return null; } } /** * 美国饮品制造工厂 * 制造咖啡和碳酸饮料 */ public class AmericaDrinksFactory implements AbstractDrinksFactory { @Override public Coffee createCoffee() { // TODO Auto-generated method stub return new Latte(); } @Override public Tea createTea() { // TODO Auto-generated method stub return null; } @Override public Sodas createSodas() { // TODO Auto-generated method stub return new CocaCola(); } } /** * 抽象工厂测试类 * */ public class AbstractFactoryTest { static void print(Drink drink){ if(drink == null){ System.out.println("产品:--" ); }else{ System.out.println("产品:" + drink.getName()); } } public static void main(String[] args) { AbstractDrinksFactory chinaDrinksFactory = new ChinaDrinksFactory(); Coffee coffee = chinaDrinksFactory.createCoffee(); Tea tea = chinaDrinksFactory.createTea(); Sodas sodas = chinaDrinksFactory.createSodas(); System.out.println("中国饮品工厂有如下产品:"); print(coffee); print(tea); print(sodas); AbstractDrinksFactory americaDrinksFactory = new AmericaDrinksFactory(); coffee = americaDrinksFactory.createCoffee(); tea = americaDrinksFactory.createTea(); sodas = americaDrinksFactory.createSodas(); System.out.println("美国饮品工厂有如下产品:"); print(coffee); print(tea); print(sodas); } } ~~~ **总结:** **简单工厂**:一个工厂,通过给工厂类传入不同的参数,产生不同的产品。不能算是真正意义上的设计模式,但可以将客户程序从具体类解耦。(**一个产品接口**) **工厂方法**:在单工厂的基础上,为不同的产品创建不同的工厂类(工厂类往往只有一个方法)使用继承,把对象的创建委托给子类,由子类来实现创建方法,可以看作是抽象工厂模式中只有单一产品的情况。(**一个产品接口、一个工厂接口-包含一个方法**) 抽象工厂:在单工厂的基础上,为不同的产品创建不同的工厂类(工厂类往往只有多个方法,来创建不同的产品)使用继承使对象的创建被实现在工厂接口所暴露出来的方法中。(**一个产品接口、一个工厂接口-包含多个方法**)