努力保头发的打工人
努力保头发的打工人
发布于 2020-12-12 / 19 阅读 / 0 评论 / 0 点赞

工厂模式

1.概述

工厂就是将零件组装成成品的地方。例如,汽车成品做好交由4S店或者汽贸城的门店销售,复杂的汽车生产在工厂完成。这样其实就是解耦,工厂设在郊区,地皮便宜而且加工复杂且嘈杂,销售设在繁华的城市里。

对比代码也是一样的,有一些对象常常需要复杂的创建过程,如果把这些放在构造函数中,会极大影响代码的可读性。而且有多个相似的类时,可能会产生大量的重复代码。这时就不妨定义一个类来专门负责对象的创建,这样的类就是工厂类,这种做法就叫作工厂模式,任何需要生成复杂对象的地方都可以使用工厂模式。

设计模式中工厂模式包含:工厂方法模式和抽象工厂模式。一般情况下,可以细分为:简单工厂模式、工厂方法模式和抽象工厂模式,简单工厂模式可以理解为工厂方法模式的一种特例。

2.工厂模式详解

2.1 工厂方法模式

2.1.1 定义

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

工厂方法模式中,抽象产品类负责定义产品的共性,实现对事物最抽象的定义;抽象工厂类定义功能,和通用的方法,创建产品由

具体的实现类工厂来完成。工厂方法模式有很多变种,下面为较为通用的类图。

工厂方法模式类图.png

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 优缺点

优点:封装性好,高层模块只需关心工厂类就行,不必关心对象如何创造出来的。

缺点:产品族扩展困难。如果要增加一个火车的产品。抽象工厂类和实现类都要修改。但是如果要增加一个豪华级别就相对容易,只需增加两个豪华的产品,和一个豪华的工厂实现类,不需要修改其他代码。