工厂模式
工厂模式有许多变体,其中最常见的有三种
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
简单工厂代码分析
UML图中我们可以清晰的看到代码结构 ,首先我们创建一个Car的汽车接口,定制汽车的基本规范,汽车可以的方法是可以跑,所以我们定义了一个抽象的run方法.
- 定义汽车接口Car
public interface Car {
void run();
}
接着我们分别定义实现了汽车接口的不同车型
- 宝马类BMW
public class BMW implements Car{
@Override
public void run() {
System.out.println("宝马正在启动~~");
}
}
- 奔驰类Benz
public class Benz implements Car{
@Override
public void run() {
System.out.println("奔驰正在启动~~");
}
}
- 比亚迪类BYD
public class BYD implements Car{
@Override
public void run() {
System.out.println("比亚迪启动发现没电了~~");
}
}
- 接着我们创建工厂类
public class CarFactory {
public static Car createCar(String type){
if ("宝马".equals(type)){
return new BMW();
}else if ("奔驰".equals(type)){
return new Benz();
}else if ("比亚迪".equals(type)){
return new BYD();
}else{
return null;
}
}
}
在上面这个工厂类中,我们通过传入的字符串equals我们要创建的车型是哪一款,匹配上的就创建并返回
- 编写测试类进行测试
public class Main {
public static void main(String[] args) {
//用工厂创建一辆宝马
Car car1 = CarFactory.createCar("宝马");
if (car1!=null){
car1.run();
}else {
System.out.println("没有该车型,无法创建!");
}
//用工厂创建一辆奔驰
Car car2 = CarFactory.createCar("奔驰");
if (car2!=null){
car2.run();
}else {
System.out.println("没有该车型,无法创建!");
}
//用工厂创建一辆宝骏
Car car3 =CarFactory.createCar("宝骏");
if (car3!=null){
car3.run();
}else {
System.out.println("没有该车型,无法创建!");
}
}
}
运行结果
为什么工厂模式多种变体呢? 其实每一种变体都有优缺点,没有任何一种设计模式是完美的
对于简单工厂模式来说,他的工厂类是一般是静态的,因此可以直接用类名直接调用工厂方法,来创建实例对象
优点是实现简单,
缺点是缺点是当需要新增产品的时候,要修改工厂类的代码,不符合开闭原则.
工厂方法模式
工厂方法模式代码分析
在类图中,相比简单工厂模式,我们新增了一个工厂接口,不同的汽车厂商实现了工厂类
汽车接口和各个不同的品牌车代码同上
- 工厂接口
public interface Factory {
Car creatCar();
}
我们在接口中声明了一个创建汽车的抽象方法
接下来,我们编写不同的汽车实现类
- 宝马汽车工厂类BMWFactory
public class BMWFactory implements Factory{
@Override
public Car creatCar() {
return new BMW();
}
}
- 奔驰汽车工厂类BenzFactory
public class BenzFactory implements Factory{
@Override
public Car creatCar() {
return new Benz();
}
}
- 比亚迪汽车工厂类BYDFactory
public class BYDFactory implements Factory{
@Override
public Car creatCar() {
return new BYD();
}
}
以上三个类它们都实现了工厂接口
接下类我们编写测试方法,来创建汽车实例,并调用汽车的方法
public class Main {
public static void main(String[] args) {
BMWFactory bmwFactory = new BMWFactory();
Car BMWx5 = bmwFactory.creatCar();
BMWx5.run();
}
}
运行结果
工厂方法模式定义一个抽象工厂接口,该接口中声明了一个用于创建产品的工厂方法,具体的产品类由具体的工厂类来实现。工厂方法模式可以有多个具体的工厂类,每个具体工厂类负责创建一种产品。
优点是符合开闭原则,当需要新增产品时,只需要新增具体的产品类和对应的具体工厂类即可,不需要修改抽象工厂接口和抽象工厂类的代码。
缺点是增加了系统的复杂程度
抽象工厂模式
为了方便包管理,我们将包进行了分类,如下
新增了一个包Logos,在该包中定义了一个名字叫做Logos的接口
- Logos接口
public interface Logos {
void showLogos();
}
我们可以看到,这个接口的接口方法是用于创建车标的,接下类每一个实现它的类,都要重写这个接口方法
- BMWLogos类 (Logos的实现类,用于创建宝马车标)
public class BMWLogos implements Logos{
@Override
public void showLogos() {
System.out.println("我的LOGO是宝马");
}
}
- BenzLogos类 (Logos的实现类,用于创建奔驰车标)
public class BuziLogos implements Logos{
@Override
public void showLogos() {
System.out.println("我的LOGO是奔驰~");
}
}
- BYDLogos类 (Logos的实现类,用于创建BYD车标)
public class BYDLogos implements Logos{
@Override
public void showLogos() {
System.out.println("我的LOGO是 比亚迪");
}
}
接着我们创建工厂接口
- 工厂接口Factory
public interface Factory {
Car createCar();
Logos createLogos();
}
这个接口中,我们声明了两个接口方法,一个用于创建车辆,一个用于创建车标,接下来每一个实现工厂的接口都要进行重写这两个方法
- 宝马族工厂类 BMWFamilyFactory
public class BMWFamilyFactory implements Factory {
@Override
public Car createCar() {
return new BMW();
}
@Override
public Logos createLogos() {
return new BMWLogos();
}
}
- 奔驰族工厂类 BenzFamilyFactory
public class BenzFamilyFactory implements Factory{
@Override
public Car createCar() {
return new Benz();
}
@Override
public Logos createLogos() {
return new BuziLogos();
}
}
- 比亚迪族工厂类 BYDFamilyFactory
public class BYDFamilyFactory implements Factory{
@Override
public Car createCar() {
return new BYD();
}
@Override
public Logos createLogos() {
return new BYDLogos();
}
}
细心的你会发现,相比于上面的工厂方法模式,这里的工厂实现类名字都会多一个Family,为什么呢?
因为抽象工厂方法模式是用来创建产品的一系列实例的,每个具体工厂类只能创建属于自己产品族的产品对象,不同产品族的产品对象不能混淆。
- 测试类
public class Main {
public static void main(String[] args) {
//创建奔驰工厂
Factory benzFamilyFactory = new BenzFamilyFactory();
benzFamilyFactory.createCar().run();//创建一辆奔驰并且使用run方法
benzFamilyFactory.createLogos().showLogos();
BMWFamilyFactory bmwFamilyFactory = new BMWFamilyFactory();
bmwFamilyFactory.createCar().run();//创建一辆奔驰并且使用run方法
bmwFamilyFactory.createLogos().showLogos();//创建一辆奔驰LOGO并且显示LOGO
}
}
运行结果
抽象工厂模式的优点在于,它能够保证创建的产品对象之间的兼容性。因为每个具体工厂类只能创建属于自己产品族的产品对象,所以不同产品族之间的产品对象不会产生冲突。此外,抽象工厂模式还支持增加新的产品族,而不需要修改已有的代码,符合开闭原则。但是,抽象工厂模式也有一些缺点。由于抽象工厂接口需要定义一组用于创建不同产品族的方法,因此当新增加一个产品族时,需要修改抽象工厂接口及其所有实现类,这可能会导致一定的代码修改工作量。
总结
简单工厂模式:
由一个工厂类根据传入的参数决定创建哪种产品类的实例。简单工厂模式将对象的创建和使用分离开来,客户端只需要传入参数,就可以得到所需的对象,无需关心对象的创建细节。
工厂方法模式:
定义一个创建产品对象的接口,由子类决定实例化哪一个产品类。工厂方法模式将对象的创建延迟到子类中去实现,客户端只需要知道所需产品的工厂类即可,无需关心具体的产品类。
抽象工厂模式:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式可以看作是工厂方法模式的升级版,它支持创建一组相关的产品对象。抽象工厂模式能够保证创建的产品对象之间的兼容性,但是新增加一个产品族时需要修改抽象工厂接口及其所有实现类。
简单工厂模式:
优点:
- 工厂类中包含了必要的逻辑判断,可以根据客户端的请求动态地创建相关的产品对象,客户端无需知道具体的产品类。
- 简单工厂模式将对象的创建和使用分离开来,客户端只需要关心所需产品的参数,无需关心对象的创建细节。
缺点:
- 简单工厂模式工厂类职责过重,增加新的产品需要修改工厂类的判断逻辑,违背了开闭原则。
- 简单工厂模式只支持一种产品族的创建,不支持扩展。
工厂方法模式:
优点:
- 工厂方法模式将对象的创建延迟到子类中去实现,符合开闭原则,新增加产品时只需要添加对应的工厂类即可。
- 工厂方法模式支持扩展,可以创建多个产品族的对象。
缺点:
- 工厂方法模式需要新增加相应的工厂类,增加了代码的复杂度。
- 工厂方法模式增加了系统的抽象性和理解难度。
抽象工厂模式:
优点:
- 抽象工厂模式能够保证创建的产品对象之间的兼容性,因为每个具体工厂类只能创建属于自己产品族的产品对象,不同产品族的产品对象不能混淆。
- 抽象工厂模式支持增加新的产品族,而不需要修改已有的代码,符合开闭原则。
缺点:
- 抽象工厂模式需要新增加相应的接口及实现类,增加了代码的复杂度。
单工厂模式只支持一种产品族的创建,不支持扩展。工厂方法模式:
优点:
- 工厂方法模式将对象的创建延迟到子类中去实现,符合开闭原则,新增加产品时只需要添加对应的工厂类即可。
- 工厂方法模式支持扩展,可以创建多个产品族的对象。
缺点:
- 工厂方法模式需要新增加相应的工厂类,增加了代码的复杂度。
- 工厂方法模式增加了系统的抽象性和理解难度。
抽象工厂模式:
优点:
- 抽象工厂模式能够保证创建的产品对象之间的兼容性,因为每个具体工厂类只能创建属于自己产品族的产品对象,不同产品族的产品对象不能混淆。
- 抽象工厂模式支持增加新的产品族,而不需要修改已有的代码,符合开闭原则。
缺点:
- 抽象工厂模式需要新增加相应的接口及实现类,增加了代码的复杂度。
- 抽象工厂模式增加了系统的抽象性和理解难度。