-
工厂模式在日常的开发中是非常常见的一种模式,他让我们在创建对象的时候不需要关注是如何创建的,只要直接使用工厂提供的方法就可以.
-
常见的工厂模式一共有三种:简单工厂模式,工厂方法模式,抽象工厂模式
在使用这三种模式之前,先看一个小案例.
准备去买车了,来到4S店看车.店里有奔驰,宝马.直接看代码写把.
- 编写一个 抽象的 Car 类,可以定义所有汽车通用的功能.
public abstract class Car {
public abstract String getName();
}
- 定义一个 宝马车的类.并且继承 Car 类
public class BaoMaCar extends Car{
public String getName(){
return "宝马!";
}
}
- 定义一个 奔驰车的类,继承 Car 类
public class BenChiCar extends Car{
public String getName(){
return "奔驰!";
}
}
- 定义汽车销售店类 CarStore ,汽车应该在这里展示,并且根据需要看不同的车.
public class CarStore {
public Car showCar(String carName){
Car car;
if ("baoma".equals(carName)){
car = new BaoMaCar();
}else if ("benchi".equals(carName)){
car = new BenChiCar();
}else {
throw new RuntimeException("没有这个车");
}
return car;
}
}
- 来一个测试类
public static void main(String[] args) {
CarStore carStore = new CarStore();
Car baoma = carStore.showCar("baoma");
System.out.println(baoma.getName());
}
执行这个 main 方法.我们可以得到结果是 宝马.这样虽然简单粗暴,但是很明显这样不可以,因为我们的代码耦合度太高的了,如果在有其他的汽车,那么在 CarStore 中需要增加很多的分支,这违反了我们书写代码的开闭原则.
那么想要解决这个问题就可以使用工厂模式.
简单工厂模式
-
其实简单工厂模式 并不是一种设计模式,他更多是的一种编程的习惯.看看他是怎么使用的吧.
-
创建汽车生产工厂 CarFactory ,用来生产想要的汽车.
public class CarFactory {
public Car createCar(String carName) {
Car car;
if ("baoma".equals(carName)){
car = new BaoMaCar();
}else if ("benchi".equals(carName)){
car = new BenChiCar();
}else {
throw new RuntimeException("没有这个车");
}
return car;
}
}
- 修改上面代码中的 CarStore 类
public Car showCar(String carName){
return new CarFactory().createCar(carName);
}
- 修改 main 方法测试
public static void main(String[] args) {
CarFactory factory = new CarFactory();
Car baoma = factory.createCar("baoma");
System.out.println(baoma.getName());
}
再次执行 main 方法,会发现结果依然是对的.
简单工厂模式的优缺点:
- 优点: 将对象的创建直接的交给具体的工厂,实现了创建和使用的分离
- 缺点: 并没有真正解决之前的代码耦合问题,如果新增汽车,需要修改代码,增加新的分支.
工厂方法模式
- 定义创建对象的接口,子类去定要实例化的类,把类的实例化推到了之类上.
- 定义 抽象的 CarFactory 类,并且定义子类需要去实现的方法.
public abstract class CarFactory {
public abstract Car showCar();
}
- 定义具体的 BenChiFactory, BaoMaFactory 工厂实现类.
public class BaoMaFactory extends CarFactory{
@Override
public Car showCar() {
return new BaoMaCar();
}
}
public class BenChiFactory extends CarFactory{
@Override
public Car showCar() {
return new BenChiCar();
}
}
- 编写测试代码去执行查看结果.
Car car = new BaoMaFactory().showCar();
Car car1 = new BenChiFactory().showCar();
System.out.println(car.getName());
System.out.println(car1.getName());
可以得到具体的执行结果为 宝马,奔驰.
工厂方法模式的优缺点:
- 优点:遵循了开闭原则,扩展性强.如果有新增的需求,只需要增加对应的工厂去继承抽象工厂就行.
- 缺点:需求多的情况下,类的数量特别的多.
抽象工厂模式
- 提供一个接口,用于同种种类的物品,并不需要去指定具体的类.
- 修改一下 CarFactory 这个抽象类为一个接口
public interface CarFactory {
Car showCar();
Bicycle showBicycle();
}
- 增加 Bicycle 相关的类
public abstract class Bicycle {
public abstract String getName();
}
public class BaoMaBicycle extends Bicycle{
public String getName(){
return "宝马自行车";
}
}
public class BenChiBicycle extends Bicycle{
public String getName(){
return "奔驰自行车";
}
}
- 修改 BaoMaFactory,BenchiFactroy
public class BaoMaFactory implements CarFactory{
@Override
public Car showCar() {
return new BaoMaCar();
}
@Override
public Bicycle showBicycle() {
return new BaoMaBicycle();
}
}
public class BenChiFactory implements CarFactory{
@Override
public Car showCar() {
return new BenChiCar();
}
@Override
public Bicycle showBicycle() {
return new BenChiBicycle();
}
}
- 修改测试类
public static void main(String[] args) {
CarFactory baoMaFactory = new BaoMaFactory();
CarFactory benChiFactory = new BenChiFactory();
System.out.println(baoMaFactory.showCar().getName());
System.out.println(baoMaFactory.showBicycle().getName());
System.out.println(benChiFactory.showCar().getName());
System.out.println(benChiFactory.showBicycle().getName());
}
执行可以得到下面的结果:
宝马!
宝马自行车
奔驰!
奔驰自行车
抽象工厂模式的优缺点;
- 优点:增加同一个“工厂“中能生产的物品吧时比较方便.
- 缺点:比较复杂,可读性差.
小彩蛋
简单工厂模式+配置文件的使用
public class CarFactory {
// 用来存储对象的容器
private static Map<String, Car> map = new HashMap<>();
static {
Properties properties = new Properties();
// 获取到配置文件的数据
InputStream inputStream = CarFactory.class.getClassLoader().getResourceAsStream("bean.properties");
try {
// 加载该数据源
properties.load(inputStream);
Set<Object> keySet = properties.keySet();
for (Object key : keySet) {
// 获取到应该创建的对象的全类名
String classname = properties.getProperty((String) key);
// 通过反射创建对应的对象
Class<?> aClass = Class.forName(classname);
Car car = (Car) aClass.newInstance();
map.put((String) key, car);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Car getCar(String carName) {
return map.get(carName);
}
}
注意这个要放在resource文件夹下
BaoMa=com.gxtna.demo.test.BaoMaCar
BenChi=com.gxtna.demo.test.BenChiCar
public static void main(String[] args) {
System.out.println(CarFactory.getCar("BaoMa").getName());
}
这个其实就是sping 加载的bean 的基本原理