工厂设计模式
一、主要解决的问题场景
1、实例化对象不使用new
,用工厂方法代替
2、将选择实现类、创建对象统一管理控制,从而将调用者跟我们的实现类解耦
二、三种工厂模式
2.0 案例场景
我们建造一个CAR
汽车类,然后又很多品牌的汽车将其实现,消费者会去购买对应的汽车品牌,我们一般的处理办法如下:
//定义接口CAR
public interface Car {
void getCarInfo();
}
//多种实现类
public class Tesla implements Car {
@Override
public void getCarInfo() {
System.out.println("购买一辆特斯拉!");
}
}
public class Lamborghini implements Car {
@Override
public void getCarInfo() {
System.out.println("购买一辆兰博基尼-毒药!");
}
}
public class Bugatti implements Car {
@Override
public void getCarInfo() {
System.out.println("购买一辆布加迪-威龙!");
}
}
消费者调用的时候就需要直接new
对象
@Test
public void testConsumer() {
Car car1 = new Tesla();
Car car2 = new Lamborghini();
Car car3 = new Bugatti();
car1.getCarInfo(); //log:购买一辆特斯拉!
car2.getCarInfo(); //log:购买一辆兰博基尼-毒药!
car3.getCarInfo(); //log:购买一辆布加迪-威龙!
}
new
就意味着创建,从生活角度看,也不可能让消费者自己从0到1生成自己想要的汽车。
从代码角度来看,调用方和我们的实现类之间的耦合性很高,如果类参数很多,这会非常的麻烦,代码也会冗余。
违背依赖倒置原则和迪米特原则。
2.1 简单工厂
那么我们可以使用一个工厂模式,将实现方式封装在里面,对外只提供一个或多个方法,消费者只需将自己的需求传递过来即可。
/**
* 汽车品牌枚举:让客户选择品牌,保证在工厂生产范围内
*/
@Getter
@AllArgsConstructor
public enum CarBrandEnum {
TESLA("Tesla", "世界上最'安全'的电动车,就是刹不住"),
LAMBORGHINI("Lamborghini", "发售限量款的兰博基尼-毒药,先到先得"),
BUGATTI("Bugatti", "发售限量款的布加迪威龙,先到先得");
/**
* 品牌名称
*/
private String brandName;
/**
* 品牌描述
*/
private String desc;
}
/**
* 汽车工厂类
*/
public class CarFactory {
/**
* 从汽车工厂获取汽车
* @param brandEnum 品牌枚举
* @return 返回对应的汽车类
*/
public static Car getCar(CarBrandEnum brandEnum) {
switch (brandEnum) {
case TESLA:
return new Tesla();
case LAMBORGHINI:
return new Lamborghini();
case BUGATTI:
return new Bugatti();
default:
return null;
}
}
}
/**
* 消费者调用
*/
@Test
public void testConsumer() {
Car car = CarFactory.getCar(CarBrandEnum.BUGATTI);
car.getCarInfo(); //log:Bugatti:发售限量款的布加迪威龙,先到先得
}
如果我们需要新增一个Mercedes-Benz
梅赛德斯-奔驰类,就不得不对getCar(CarBrandEnum brandEnum)
方法进行修改,所以我们可以在汽车工厂类中提供多个方法,调用方只是调用不同的方法。
/**
* 获取奔驰汽车
*/
/**
* 汽车工厂类
*/
public class CarFactory {
/**
* 奔驰车获取方法
*/
public static Car getBenz() {
return new Benz();
}
//……其他的汽车品牌的获取方法
}
简单工厂调用图 |
---|
![]() |
以上就是简单工厂的模式,简单工厂也被成为静态工厂
,但是有弊端:
需求变更,必须修改原类或者原类中的方法,违背
开闭原则
2.2 工厂方法模式
为了解决简单工厂的开闭问题,我们可以再加一层工厂接口
,每个品牌有自己的工厂,消费者根据需求去调用对应车品牌的工厂即可,毕竟没有什么东西是加一层解决不了的,如果不行,那就加两层。
工厂方法模式 |
---|
![]() |
/**
* 工厂方法接口
*/
public interface MethodFactory {
Car getCar();
}
/**
* @兰博基尼工厂实现类,内部实现制造兰博基尼-毒药
*/
public class LamborghiniFactory implements MethodFactory {
@Override
public Car getCar() {
return new Lamborghini();
}
}
/**
* 消费者调用
*/
@Test
public void testConsumer() {
MethodFactory factory = new LamborghiniFactory();
Car car = factory.getCar();
car.getCarInfo(