来源:https://blog.csdn.net/ayunlong/article/details/130297293?spm=1001.2014.3001.5502
Java设计模式-工厂模式(Singleton Pattern)
工厂模式完成了对象创建过程的封装,对外屏蔽实现过程
一、什么是工厂模式 工厂模式的出现是为了解决创建对象实例的问题,通常我们使用new关键字创建某个对象,但在特定的情况下,一个对象的创建需要一些列的步骤,依赖其它的模块对象,所以这类对象的创建更像是一个过程 ,而非单个动作。这与工厂的工作模式极为相似,工厂中制造一个汽车,比如要从全世界各地购买零部件,然后组装为一台汽车,而这个组装的过程,就是工厂模式的创建汽车的过程。
二、3种工厂模式的实现 简单工厂模式(Simple Factory) 简单工厂模式完成了最原始、最简单的对象创建与业务逻辑的隔离,降低了耦合性 特点:
所有的对象都在一个工厂中创建
完成了对象创建功能和对象使用的隔离,封装了创建的过程
根据传递的参数即可创建不同对象,较为灵活
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package org.factory.simpleFactory;abstract class Car { public Car () { this .build(); } public abstract void build () ; } class BMW extends Car { public void build () { System.out.println("生产一台BMW" ); } } class Benz extends Car { public void build () { System.out.println("生产一台Benz" ); } } class CarFactory { public Car createCar (String type) { Car car = null ; if (type == "bmw" ){ car = new BMW (); } else if (type == "benz" ) { car = new Benz (); } return car; } } public class Client { public static void main (String[] args) { CarFactory carFactory = new CarFactory (); BMW bmw = (BMW) carFactory.createCar("bmw" ); Benz benz = (Benz) carFactory.createCar("benz" ); } }
但很显然这种方式有很多问题
违反开闭原则,想要增加新对象,就要修改工厂类
扩展性差,if else太多,不够优雅,而且如果创建几百个类型的对象,工程类的维护会令人发指
但简单工厂模式也有自己的应用场景,例如在相对简单业务场景下,JDK中的Calendar类就使用了简单工厂模式。
工厂方法模式(Factory Method) 简单工厂的最大缺点在于工厂类不够灵活,工厂方法模式便将工厂进行抽象化,定义创建对象的接口,具体如何实现对象的创建,交给具体的工厂类。那么此时想要新增产品,只需要扩展实现抽象工厂类即可,符合开闭原则。 当使用者想要创建某个对象时,只需要找到对应的工厂,即可创建。工厂方法模式需要以下角色
抽象工厂 AbstractFactory: 定义创建对象的接口,具体由具体工厂实现
具体工厂 Factory:实现抽象工厂的接口,实现创建对象的过程
抽象产品 AbstractProduct:所有具体产品的父类,可以满足里氏替换的设计原则
具体产品 Product:工厂所建实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package org.factory.factoryMethod;abstract class Car { public Car () { this .build(); } public abstract void build () ; } class BMW extends Car { public void build () { System.out.println("生产一台BMW" ); } } class Benz extends Car { public void build () { System.out.println("生产一台Benz" ); } } abstract class Factory { public abstract Car create () ; } class BMWFactory extends Factory { public BMW create () { return new BMW (); } } class BenzFactory extends Factory { public Benz create () { return new Benz (); } } public class Client { public static void main (String[] args) { BenzFactory benzFactory = new BenzFactory (); benzFactory.create(); BMWFactory bmwFactory = new BMWFactory (); bmwFactory.create(); } }
总结下上面的代码UML图 方法工厂有很多优点
扩展性强:方法工厂模式限定了某个工厂只能创建某个对象,只要知道工厂名字就可以知道他创建的对象是什么,而且扩展性极强,如果增加五菱汽车,只需要增加一个五菱工厂类和五菱汽车对象即可。
屏蔽产品:产品的变化与调用者无关,这有点像“中间层理念”,例如Java的JDBC连接,我们只需要更改驱动名称即可,其它的不需要关心,十分强大!
解耦:这个特性是所有的设计模式都有的优点,符合依赖倒置原则,值依赖产品类的抽象;也符合里氏替换原则,可以使用子类替换父类,符合迪米特法则,我只需要操作Factory,不操作触产品类方法。
方法工厂一般在抽象类的实现类会不断变化时会使用,例如信息通知功能,可以短信、可以是邮件、可以是抖音,在未来可能是其它的方式
抽象工厂模式(Abstract Factory) 抽象模式是最难理解的模式,首先,观察方法工厂模式,有没有发现方法工厂模式中只用到了一种“产品”?需要Create,直接就创建了一个对象,但我们回想下工厂制造汽车的场景,更多的是在“组装”。例如创建一个汽车需要:轮胎、天窗、底盘等,而这三个都是单独的对象。
这就很明确了:我生成一个宝马需要天窗、底盘等产品,接下来通过代码实现上面的需求(也可以先看代码后面的UML图,再回头看代码,会更高效)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 package org.factory.abstractFactory;abstract class Tyre { public Tyre () { this .getName(); this .getColor(); } public abstract void getColor () ; public abstract void getName () ; } class TyreA extends Tyre { public void getColor () { System.out.println("轮胎A的颜色是黑色" ); } public void getName () { System.out.println("轮胎A的名字是轮胎A" ); } } class TyreB extends Tyre { public void getColor () { System.out.println("轮胎B的颜色是红色" ); } public void getName () { System.out.println("轮胎B的名字是轮胎B" ); } } abstract class Window { public Window () { this .open(); this .close(); } public abstract void open () ; public abstract void close () ; } class WindowA extends Window { public void open () { System.out.println("WindowA会开窗" ); } public void close () { System.out.println("WindowA会关窗" ); } } class WindowB extends Window { public void open () { System.out.println("WindowB会开窗" ); } public void close () { System.out.println("WindowB会关窗" ); } } abstract class Car { public abstract void setWindow (Window window) ; public abstract void setTyre (Tyre tyre) ; } class BMW extends Car { private Window window; private Tyre tyre; public void setWindow (Window window) { this .window = window; } public void setTyre (Tyre tyre) { this .tyre = tyre; } } class Benz extends Car { private Window window; private Tyre tyre; public void setWindow (Window window) { this .window = window; } public void setTyre (Tyre tyre) { this .tyre = tyre; } } interface Factory { public Window createWindow () ; public Tyre createTyre () ; public Car create () ; } class BMWFactory implements Factory { public BMW create () { System.out.println("开始生产BMW" ); BMW bmw = new BMW (); bmw.setTyre(createTyre()); bmw.setWindow(createWindow()); return bmw; } public Window createWindow () { return new WindowB (); } public Tyre createTyre () { return new TyreA (); } } class BenzFactory implements Factory { public Benz create () { System.out.println("开始生产Benz" ); Benz benz = new Benz (); benz.setTyre(createTyre()); benz.setWindow(createWindow()); return benz; } public Window createWindow () { return new WindowB (); } public Tyre createTyre () { return new TyreB (); } } public class Client { public static void main (String[] args) { BMWFactory bmwFactory = new BMWFactory (); bmwFactory.create(); BenzFactory benzFactory = new BenzFactory (); benzFactory.create(); } } 开始生产BMW 轮胎A的名字是轮胎A 轮胎A的颜色是黑色 WindowB会开窗 WindowB会关窗 开始生产Benz 轮胎B的名字是轮胎B 轮胎B的颜色是红色 WindowB会开窗 WindowB会关窗
代码很多,表达出了抽象工厂的使用方法,抽象工厂有很多优点
封装性:Factory屏蔽了技术细节,使得高层模块只关心抽象和接口即可,工厂负责创建实例
产品族内的约束为非公开状态:高层模块只知道工厂会返回我一个宝马,但宝马内部用的什么材料我不清楚,但你给我一个宝马实例即可,具体的产品族内的约束是在工厂内实现的
缺点也很明显,产品(宝马)的扩展很困难,如果在宝马中增加后备箱,想一下需要改哪些地方?
首先Factory接口、BMWFactory肯定要修改,因为要增加createHouBX方法
Car接口以及实现类都要增加setHouBX的方法
增加HouBX类和实现类(这是没什么问题的)
所以主要问题是要修改Factory/Car接口,这是违反开闭原则的。所有实现Factory/Car的类都要修改、测试。
总结下:
在产品中增加零部件是困难的(例如宝马增加后备箱)
增加产品的种类是容易得(增加五菱汽车)
抽象模式比作数据库连接切换的话,可以理解为虽然便于两数据库之间的切换,但是不便于增加需求功能。
对比下三种工厂模式
简单工厂:只有唯一工厂(简单工厂),一个产品接口/抽象类,根据简单工厂中的静态方法来创建具体产品对象。适用于产品较少,几乎不扩展的情景
工厂方法:有多个工厂(抽象工厂+多个具体工厂),一个产品接口/抽象类,根据继承抽象工厂中的方法来多态创建具体产品对象。适用于一个类型的多个产品
抽象方法:有多个工厂(抽象工厂+多个具体工厂),多个产品接口/抽象类,对产品子类进行分组,根据继承抽象工厂中的方法多态创建同组的不同具体产品对象。适用于多个类型的多个产品,例如BenzFactory在创建汽车时,可以使用WindowA也可以使用WindowB。
三、JavaSE中工厂模式的使用 首先列举下使用工厂模式的类(看到名为newInstance的方法,大概率就是工厂模式)
java.util.Calendar 类 getInstance 方法使用了简单工厂
java.lang.Class 类的 newInstance 方法
java.lang.Class 类的 forName 方法
java.lang.reflect.Array 类的 newInstance 方法
java.lang.reflect.Constructor 类的 newInstance 方法
java.lang.reflect.Proxy 类的 newProxyInstance 方法
JDK 中8 种基本类型的包装类 Integer、Long、Short、Character、Byte、Float、Double、Boolean 的 valueOf 方法使用了简单工厂,可以根据参数创建不同的对象