1.概述
工厂就是将零件组装成成品的地方。例如,汽车成品做好交由4S店或者汽贸城的门店销售,复杂的汽车生产在工厂完成。这样其实就是解耦,工厂设在郊区,地皮便宜而且加工复杂且嘈杂,销售设在繁华的城市里。
对比代码也是一样的,有一些对象常常需要复杂的创建过程,如果把这些放在构造函数中,会极大影响代码的可读性。而且有多个相似的类时,可能会产生大量的重复代码。这时就不妨定义一个类来专门负责对象的创建,这样的类就是工厂类,这种做法就叫作工厂模式,任何需要生成复杂对象的地方都可以使用工厂模式。
设计模式中工厂模式包含:工厂方法模式和抽象工厂模式。一般情况下,可以细分为:简单工厂模式、工厂方法模式和抽象工厂模式,简单工厂模式可以理解为工厂方法模式的一种特例。
2.工厂模式详解
2.1 工厂方法模式
2.1.1 定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式中,抽象产品类负责定义产品的共性,实现对事物最抽象的定义;抽象工厂类定义功能,和通用的方法,创建产品由
具体的实现类工厂来完成。工厂方法模式有很多变种,下面为较为通用的类图。
2.1.2 示例代码
创建产品抽象以及具体产品类,
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 领克车型接口
*/
public interface LynkCo {
/**
* 能坐人
*/
void canSit();
/**
* 能跑
*/
void canRun();
}
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 领克01是款SUV
*/
public class LynkCo01 implements LynkCo {
/**
* 能坐人
*/
@Override
public void canSit() {
System.out.println("01:后排宽敞的很,甚至还能跷二郎腿!");
}
/**
* 能跑
*/
@Override
public void canRun() {
System.out.println("01:动力还行,操控就那样!");
}
}
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 领克家用轿车车型
*/
public class LynkCo03 implements LynkCo{
/**
* 能坐人
*/
@Override
public void canSit() {
System.out.println("03:后排一般,能坐就行!");
}
/**
* 能跑
*/
@Override
public void canRun() {
System.out.println("03:动力还行,操控还行!");
}
}
创建抽象工厂以及具体工厂类,
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 工厂抽象类
*/
public abstract class AbstractCarFactory {
/**
* 造车抽象方法
*
* @param c 具体车型
* @author chiangtaol
*/
public abstract <T extends LynkCo > T buildCar(Class<T> c);
}
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 造车具体工厂类
*/
@Slf4j
public class CarFactory extends AbstractCarFactory{
/**
* 造车抽象方法
*
* @param c 具体车型
* @author chiangtaol
*/
@Override
public <T extends LynkCo> T buildCar(Class<T> c){
LynkCo lynkCo = null;
try {
lynkCo = (LynkCo) Class.forName(c.getName()).getConstructor().newInstance();
} catch (Exception e) {
log.warn("创建车辆失败");
}
return (T)lynkCo;
}
}
接下来进行测试,
/**
* @author chiangtaol
* @date 2020-11-18
* @describe
*/
class CarFactoryTest {
@Test
void buildCar() {
// 初始化工厂
CarFactory carFactory = new CarFactory();
// 创建领克01车型
LynkCo01 lynkCo01 = carFactory.buildCar(LynkCo01.class);
lynkCo01.canRun();
lynkCo01.canSit();
LynkCo03 lynkCo03 = carFactory.buildCar(LynkCo03.class);
lynkCo03.canRun();
lynkCo03.canSit();
}
}
// 测试结果如下
01:动力还行,操控就那样!
01:后排宽敞的很,甚至还能跷二郎腿!
03:动力还行,操控还行!
03:后排一般,能坐就行!
2.1.3 优点
首先,良好的封装性,代码结构清晰。一个对象的创建是有条件约束的,调用者只需知道产品的类名(或者约束的字符、枚举)就可以了,不用知道创建产品的过程,降低模块间的耦合。
其次,拓展性十分优秀。在需要增加产品的情况下,只要适当修改具体工厂,或增加一个产品类工厂不需要做任何改动。
再次,屏蔽产品类。不管产品如何变化,调用者都不需要关心。
最后,工厂方法模式是典型的解耦框架。高层模块只需要知道产品的抽象类,其实现类不用关心,符合迪米特法则;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里式替换原则,使用产品子类替换产品父类。
2.1.4 使用场景
工厂方法模式是new一个对象的替代品,所以在所有的需要生成对象的地方都可以使用,但要考虑是否需要增加一个工厂类来管理,增加代码的复杂度。在需要灵活的、可扩展的框架时,可以考虑使用。例如:通知用户信息,可以使用短信、邮件、APP推送等,以后增加方式比较容易。
2.2 简单工厂模式
2.2.1 简单工厂与工厂方法区别
简单工厂就是工厂方法的一种变种,当只需要一个工厂类,没必要每次使用时都把它生成出来,使用静态方法就行。去掉抽象的工厂,将创建产品方法修改为静态方法。
2.2.2 代码示例
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 简单工厂类
*/
@Slf4j
public class SimpleFactory {
/**
* 根据类型创建汽车
* @param tClass 汽车类型
*/
public static <T extends LynkCo> T buildCar(Class<T> tClass){
LynkCo lynkCo = null;
try {
lynkCo = (LynkCo) Class.forName(tClass.getName()).getConstructor().newInstance();
} catch (Exception e) {
log.warn("简单工厂创建车辆失败!!!");
}
return (T)lynkCo;
}
/**
* 根据名称创建对应汽车
* @param name 汽车名称
*/
public static LynkCo buildCarByName(String name){
if ("01".equals(name)){
return new LynkCo01();
}else if ("03".equals(name)){
return new LynkCo03();
}else {
return null;
}
}
}
测试代码如下:
/**
* @author chiangtaol
* @date 2020-11-18
* @describe
*/
@Slf4j
class SimpleFactoryTest {
@Test
void buildCar() {
// 创建领克01车型
LynkCo01 lynkCo01 = SimpleFactory.buildCar(LynkCo01.class);
lynkCo01.canRun();
lynkCo01.canSit();
// 创建领克03车型
LynkCo03 lynkCo03 = SimpleFactory.buildCar(LynkCo03.class);
lynkCo03.canRun();
lynkCo03.canSit();
}
@Test
void buildCarByName(){
// 创建领克01车型
LynkCo lynkCo01 = SimpleFactory.buildCarByName("01");
lynkCo01.canRun();
lynkCo01.canSit();
// 创建领克03车型
LynkCo lynkCo03 = SimpleFactory.buildCarByName("03");
lynkCo03.canRun();
lynkCo03.canSit();
}
}
// 测试结果
01:动力还行,操控就那样!
01:后排宽敞的很,甚至还能跷二郎腿!
03:动力还行,操控还行!
03:后排一般,能坐就行!
2.3 抽象工厂模式
2.3.1 定义
为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
2.3.2 与工厂方法模式区别
抽象工厂模式是工厂方法模式的升级版本,当产品增多,例如生产自行车、汽车,而且有高端自行车和高端汽车。我们就可以把工厂合并。专门有工厂负责生产高端的产品,专门工厂负责生产低端产品。每个工厂都要生成自行车、汽车。相当于不同工厂负责多个产品族某种特性(例如:等级)的生产。
2.3.3 代码示例
定义两个产品族,及具体不同级别的产品
/**
* @author chiangtaol
* @date 2022-04-14
* @describe 汽车抽象类
*/
public abstract class AbstractCar {
public void run(){
System.out.println("车都可以跑");
}
public abstract void getWeight();
}
/**
* @author chiangtaol
* @date 2022-04-14
* @describe 自行车抽象类
*/
public abstract class AbstractBicycle {
public void alert(){
System.out.println("自行车都有车铃");
}
public abstract void size();
}
/**
* @author chiangtaol
* @date 2022-04-14
* @describe 汽车型号1
*/
public class Car01 extends AbstractCar{
@Override
public void getWeight() {
System.out.println("型号1车型一般小于1.5t");
}
}
/**
* @author chiangtaol
* @date 2022-04-14
* @describe 汽车型号2
*/
public class Car02 extends AbstractCar{
@Override
public void getWeight() {
System.out.println("型号2车型重量一般大于2t");
}
}
/**
* @author chiangtaol
* @date 2022-04-14
* @describe 自行车型号1
*/
public class Bicycle01 extends AbstractBicycle{
@Override
public void size() {
System.out.println("自行车型号1轮圈为20寸");
}
}
/**
* @author chiangtaol
* @date 2022-04-14
* @describe 自行车型号2
*/
public class Bicycle02 extends AbstractBicycle{
@Override
public void size() {
System.out.println("自行车型号2轮圈大小为25寸");
}
}
定义抽象工厂约束实现类必须有的功能,以及其实现类
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 多个工厂抽象类
*/
public abstract class AbstractMultiFactory {
// 创建汽车产品家族
public abstract AbstractCar buildCar();
// 创建自行车产品家族
public abstract AbstractBicycle buildBicycle();
}
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 高端类型生产
*/
public class HighEndProductFactory extends AbstractMultiFactory{
@Override
public AbstractCar buildCar() {
return new Car02();
}
@Override
public AbstractBicycle buildBicycle() {
return new Bicycle02();
}
}
/**
* @author chiangtaol
* @date 2020-11-18
* @describe 低端产品工厂
*/
public class LowEndProductFactory extends AbstractMultiFactory{
@Override
public AbstractCar buildCar() {
return new Car01();
}
@Override
public AbstractBicycle buildBicycle() {
return new Bicycle01();
}
}
2.3.3 优缺点
优点:封装性好,高层模块只需关心工厂类就行,不必关心对象如何创造出来的。
缺点:产品族扩展困难。如果要增加一个火车的产品。抽象工厂类和实现类都要修改。但是如果要增加一个豪华级别就相对容易,只需增加两个豪华的产品,和一个豪华的工厂实现类,不需要修改其他代码。