设计模式之工厂模式(创建者模式)

136 阅读4分钟
  • 工厂模式在日常的开发中是非常常见的一种模式,他让我们在创建对象的时候不需要关注是如何创建的,只要直接使用工厂提供的方法就可以.

  • 常见的工厂模式一共有三种:简单工厂模式,工厂方法模式,抽象工厂模式

在使用这三种模式之前,先看一个小案例.

准备去买车了,来到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 的基本原理