工厂模式
1. 什么是工厂模式
-
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
-
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
2. 核心本质
- 实现了创造者和调用者的分离
- 实例化对象不使用new,用工厂代替
- 将选择实现类,创建对象统一管理和控制,从而将调用者和实现类进行解耦
3. 常见场景
- 您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现
- MyBatis换数据库只需换方言和驱动就可以
4. 使用工厂模式有什么好处
- 一个调用者想创建一个对象,只要知道其名称就可以了
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
- 屏蔽产品的具体实现,调用者只关心产品的接口
5. 单例模式的缺点
我们应该知道每种设计模式的优缺点才能更好的根据实际应用情况来选择使用哪种设计模式。
- 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事
6.常见的两种工厂模式实现方式
-
简单工厂模式
用来生产同一等级结构中的任意产品(对于增加新的产品,需要修改已有代码)我们先来看一下不使用工厂模式生产对象会有什么问题
//我们首先来一个Car接口、里面就一个show方法 public interface Car{ void show(); } //创建两个实现类来实现该接口 public class WuLing implements Car{ @Override public void show(){System.out.println("五菱宏光")} } public class Tesla implements Car{ @Override public void show(){System.out.println("特斯拉")} } //我们来一个消费者的类在创建一下实例 public class Consumer{ public static void main(String[] args){ Car wuLing = new Wuling(); Car tesla = new Tesla(); //我们来看这种方法的弊端 我们设计了这个一个简单的东西,你要了解接口,还要了解所有的实现类,如果这些东西不知道的话,你就创建不出来一个对象 用OOP的思想来看这个问题的话,我们只要Car就行了里面具体的实现细节不归我们管 放到现实生活中来,我们要买一辆车,直接去4S店买就行了,不需要去关心车怎么造出来的,但是现在相当于车就是我们自己造出来的 } }
现在我们去抽象一个专门生产对象的一个工厂类
public class CarFactory{ 我们在这个工厂里面去生产对象 public static Car getCar(String carName){ if(carName == null || "".equale("")){ return null; } if("五菱宏光".equale(carName)){ return new Wuling(); }else if("特斯拉".equale(carName)){ return new Tesla(); } return null; } } 我们工厂已经创建完成,再来看下我们怎么取获取一个Car对象 Car wuLing = CarFactory.getCar("五菱宏光"); Car tesla = CarFactory.getCar("特斯拉"); 现在我们去获取对象不用去创建他,我们只需要告诉工厂,我需要一个什么样的Car对象工厂就会给我一个我需要的对象
但是这样的方法有点小瑕疵,我们来看一下
现在又要拓展一个类(大众) public class DaZhogn implements Car(){ @Override public void show(){System.out.println("大众")}; } 现在拓展一个类我们就需要在工厂里面修改我们的逻辑代码 if("五菱宏光".equale(carName)){ return new Wuling(); }else if("特斯拉".equale(carName)){ return new Tesla(); }else if("大众".equale(carName)){ return new DaZhong(); } 每次拓展一个新类的时候都要修改我们工厂里面的逻辑代码这样是不是不符合我们的开闭原则啊 开闭原则:一个软件的实体应当对拓展开放,对修改关闭 我们来优化一下这个代码 public class CarFactory{ public static Car getWuling(){return new Wuling()} public static Car getTesla(){return new Tesla()} public static Car getDaZhong(){return new DaZhong()} } 但是的方法也可以,但是我们拓展的时候还得在我们的逻辑代码里面修改,不符合我们的需求
-
工厂方法模式
用来生产同一等级结构中的固定产品(支持增加任意产品)为了完全满足我们的开闭原则,我们来使用这种方法 我们将工厂抽象成一个接口 public interface CarFactory { Car getCar(); } 给每一个类添加一个工厂类实现我们的工厂接口 五菱工厂 public class WuLingFactory implements CarFactory { @Override public Car getCar() { return new Wuling();} } 特斯拉工厂 public class TeslaFactory implements CarFactory { @Override public Car getCar() {return new Tesla();} } public class DaZhong implements CarFactory{ @Override public Car getCar(return new DaZhong();) } 这样我们在拓展一个新类的时候只需要增加一个新类的工厂类不用改动我们原来的逻辑代码,这样完全符合了我们的开闭原则
现在我们来思考一下
为了满足我们的原则这样做真的对吗,我们来对比一下两个文件
我们从几个角度来对比一下- 结构复杂度
简单工厂模式:逻辑代码在聚拢在一起结构清晰
方法工厂模式:逻辑代码分散在各个类中不够清晰 - 编程复杂度
简单工厂模式:每拓展一个类添加对象的方法
方法工厂模式:每拓展一个类为其添加一个工厂类 - 管理复杂度
简单工厂模式:代码实现都在一块更容易管理
方法工厂模式:代码分散不易管理
结论
- 根据设计原则:方法工厂模式
完全符合了我们的工厂模式和开闭原则 - 根据实际业务:简单工厂模式
我们大多数的软件都是这种模式,所以说我们的设计原则,不一定要满足他,要根据简单易用来,如果你因为一个原则,将一个应用设计得及其复杂也是有违初衷的
就像我们数据库的三大范式,有时我们为了提升索引效率可以违反三大范式适当的添加一些冗余
- 结构复杂度