工厂模式
工厂模式有许多变体,其中最常见的有三种
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
简单工厂代码分析
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 } }
运行结果
抽象工厂模式的优点在于,它能够保证创建的产品对象之间的兼容性。因为每个具体工厂类只能创建属于自己产品族的产品对象,所以不同产品族之间的产品对象不会产生冲突。此外,抽象工厂模式还支持增加新的产品族,而不需要修改已有的代码,符合开闭原则。但是,抽象工厂模式也有一些缺点。由于抽象工厂接口需要定义一组用于创建不同产品族的方法,因此当新增加一个产品族时,需要修改抽象工厂接口及其所有实现类,这可能会导致一定的代码修改工作量。
总结
简单工厂模式:
由一个工厂类根据传入的参数决定创建哪种产品类的实例。简单工厂模式将对象的创建和使用分离开来,客户端只需要传入参数,就可以得到所需的对象,无需关心对象的创建细节。
工厂方法模式:
定义一个创建产品对象的接口,由子类决定实例化哪一个产品类。工厂方法模式将对象的创建延迟到子类中去实现,客户端只需要知道所需产品的工厂类即可,无需关心具体的产品类。
抽象工厂模式:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式可以看作是工厂方法模式的升级版,它支持创建一组相关的产品对象。抽象工厂模式能够保证创建的产品对象之间的兼容性,但是新增加一个产品族时需要修改抽象工厂接口及其所有实现类。
简单工厂模式:
优点:
- 工厂类中包含了必要的逻辑判断,可以根据客户端的请求动态地创建相关的产品对象,客户端无需知道具体的产品类。
- 简单工厂模式将对象的创建和使用分离开来,客户端只需要关心所需产品的参数,无需关心对象的创建细节。
缺点:
- 简单工厂模式工厂类职责过重,增加新的产品需要修改工厂类的判断逻辑,违背了开闭原则。
- 简单工厂模式只支持一种产品族的创建,不支持扩展。
工厂方法模式:
优点:
- 工厂方法模式将对象的创建延迟到子类中去实现,符合开闭原则,新增加产品时只需要添加对应的工厂类即可。
- 工厂方法模式支持扩展,可以创建多个产品族的对象。
缺点:
- 工厂方法模式需要新增加相应的工厂类,增加了代码的复杂度。
- 工厂方法模式增加了系统的抽象性和理解难度。
抽象工厂模式:
优点:
- 抽象工厂模式能够保证创建的产品对象之间的兼容性,因为每个具体工厂类只能创建属于自己产品族的产品对象,不同产品族的产品对象不能混淆。
- 抽象工厂模式支持增加新的产品族,而不需要修改已有的代码,符合开闭原则。
缺点:
- 抽象工厂模式需要新增加相应的接口及实现类,增加了代码的复杂度。
单工厂模式只支持一种产品族的创建,不支持扩展。工厂方法模式:
优点:
- 工厂方法模式将对象的创建延迟到子类中去实现,符合开闭原则,新增加产品时只需要添加对应的工厂类即可。
- 工厂方法模式支持扩展,可以创建多个产品族的对象。
缺点:
- 工厂方法模式需要新增加相应的工厂类,增加了代码的复杂度。
- 工厂方法模式增加了系统的抽象性和理解难度。
抽象工厂模式:
优点:
- 抽象工厂模式能够保证创建的产品对象之间的兼容性,因为每个具体工厂类只能创建属于自己产品族的产品对象,不同产品族的产品对象不能混淆。
- 抽象工厂模式支持增加新的产品族,而不需要修改已有的代码,符合开闭原则。
缺点:
- 抽象工厂模式需要新增加相应的接口及实现类,增加了代码的复杂度。
- 抽象工厂模式增加了系统的抽象性和理解难度。