Java 设计模式——工厂模式(Factory Pattern)

一、工厂模式简介

在工厂模式中,创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

工厂模式分为“三种”(准确点说是两种,因为简单工厂模式是一种编程习惯)

1、简单工厂模式(Simple Factory)

      描述:又叫静态工厂,是将对象的创建包装进一个类

      优点:实现简单,使用广泛,修改时只需要修改这个类

      缺点:不能继承和改变这个方法的创建行为

2、工厂方法模式(Method Factory)

      描述:定义了一个创建对象的接口,但是由子类决定要实例化的是哪一个,将类的实例化推迟到子类

      优点:1、一个调用者想创建一个对象,只要知道其名称就可以了。

                 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

                 3、屏蔽产品的具体实现,调用者只关心产品的接口。

      缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

3、抽象工厂模式(Abstract Factory)

      描述:提供一个接口,用于创建相关或依赖对象家族,而不需要明确指定具体类

      优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

      缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体实现的里面加代码。

二、工厂模式中包含的设计原则

1、依赖倒置原则(Dependency Inversion Principle)

  • 高层模块不依赖低层模块,高层和低层模块应该依赖于抽象(“高层”组件是由“低层“组件定义其行为)
  • 接口或抽象类不依赖于实现类(如:实现类变量)
  • 实现类依赖于抽象类或接口

   总的来说是:面向接口编程,不针对实现编程,要依赖抽象,不依赖具体类。

2、开闭原则(Open-Closed Principle)

  • 对扩展开放,对修改关闭

三、工厂模式实现

以下以汽车工厂为例,通过代码来诠释工厂模式的神奇。

1、简单工厂/静态工厂(GitHub源码

假如现在有一个汽车工厂(CarFactory),需要生产两种不同品牌的车型,BenzCar和BMWCar,该怎样实现?

思路:

  1. 创建汽车对象,将汽车有相似的属性封装进Car,BenzCar和BMWCar继承Car。
  2. 创建生产方法,根据参数来判断生产哪一种车型。

创建汽车类,代码如下:

public interface Car {

    /**
     * 汽车品牌
     *
     * @return
     */
    String getBrand();
}

public class BenzCar implements Car {

    @Override
    public String getBrand() {
        return "I'm Benz.";
    }
}

public class BMWCar implements Car {

    @Override
    public String getBrand() {
        return "I'm BMW.";
    }
}

接下来是CarFactory代码:

public class CarFactory {

    public enum Kinds {
        Benz, BMW
    }

    public static Car getCar(Kinds kinds) {
        switch (kinds) {
            case BMW:
                return new BMWCar();
            case Benz:
                return new BenzCar();
        }
        return null;
    }

}

CarFactory中的方法理论上可以在调用处直接根据需求,直接生成,这里需要多创建一个CarFactory类将生成代码移到这个类中,这样的好处是当以后需要修改时,只修改这一个类,但这样的方式不能通过继承的方式来改变创建方法的行为。

2、工厂方法(Github源码

上一节讲了生成BenzCar和BMWCar两种车型,现在新的需求来了,该怎么修改呢?新需求如下:

       新增两种车型生产,SUV(越野车)和 Sedan(轿车),且增加生产流程,那么现在BMW和Benz品牌个需要生产两种车型,分别为BMWSUVCar,BMWSedan和BenzSUVCar,BenzSedanCar

在没有学习设计模式之前,我们也能实现,代码如下:

    public static Car getCar(Kinds kinds, Category category) {
        Car car = null;
        if (Kinds.Benz.equals(kinds)) {
            if (Category.Sedan.equals(category)) {
                car = new BenzSedan();
            } else if (Category.SUV.equals(category)) {
                car = new BenzSUV();
            }
        } else if (Kinds.BMW.equals(kinds)) {
            if (Category.Sedan.equals(category)) {
                car = new BMWSedan();
            } else if (Category.SUV.equals(category)) {
                car = new BMWSUV();
            }
        }
        return car;
    }

//调用
Car benzSedanCar = getCar(Kinds.Benz,Category.Sedan);
benzSedanCar.run();

Car benzSUVCar = getCar(Kinds.Benz,Category.SUV);
benzSUVCar.run();

Car BMWSedanCar = getCar(Kinds.BMW,Category.Sedan);
BMWSedanCar.run();

Car BMWSUVCar = getCar(Kinds.BMW,Category.SUV);
BMWSUVCar.run();

这样的实现方式从逻辑上来说也没毛病,功能也完全可以实现,但如果新的需求又来了呢,比如说添加新的车型,添加新的品牌,该怎样扩展? 继续if  else 的无止境下去? 就算能这样加下去,如果新增了另外一些属性呢?  是不是这个类就更复杂了,结构也会越来越混乱,这不是我们想要的。  先不说扩展性,就光依赖,这个类就够庞大的了。下面来从设计模式中心思想之一”只依赖接口,不依赖具体实现“重新理一下思路:

  1. 抽象化,针对接口编程
  2. 针对实现编程,个性化生产实现

抽象化,针对接口编程

抽象化的目的,提供接口依赖。抽象的原则是寻找相似的操作和流程,提取到父类接口(抽象类和接口)。这里可以把Benz和BMW的生产流程作为一个抽象(CarFactory),汽车本身也是一个抽象(Car),父类代码如下:

public abstract class Car {

    protected String brand;

    void prepare() {
        System.out.println("=== Start create a " + brand + " Car ===");
    }

    void chassis() {
        System.out.println("Creating chassis.");
    }

    void body() {
        System.out.println("Creating body.");
    }

    void engine() {
        System.out.println("Creating engine.");
    }

    void electrical() {
        System.out.println("Creating electrical.");
    }

    void finish() {
        System.out.println("=== The birth of a new " + brand + "Car ===");
    }

    public void run() {
        System.out.println("Hello, I'm a new " + brand + " Car.");
        System.out.println();
    }
}

public abstract class CarFactory {

    /**
     * 创建汽车
     *
     * @param item 汽车类型
     * @return
     */
    protected abstract Car createCar(String item);

    public Car newCar(String item) {
        Car car = createCar(item);
        car.prepare();
        car.chassis();
        car.body();
        car.engine();
        car.electrical();
        car.finish();
        return car;
    }

}

其中prepare(),chassis(),body(),engine(),electrical()和finish()这些是汽车的生产流程,唯一不同的是由createCar()提供的汽车类型。

针对实现编程

由于BMW和Benz的生产流程可能存在一些差异,为了避免这些差异,我们将两个工厂分开分别为BenzFactory和BMWFactory且都需要继承标准流程CarFactory。对于汽车也是如此,这里为了方便就没做区分,仅仅是从名称上来区分(在实际开发中可以根据需求再做一次抽象,分别生成BMWCar和BenzCar)。

以下的Benz和BMW的两种车型的代码,并根据Brand型号来区分:

public class BenzSedan extends Car {

    public BenzSedan() {
        brand = "Benz sedan";
    }
}

public class BenzSUV extends Car {

    public BenzSUV() {
        brand = "Benz SUV";
    }
}

public class BMWSedan extends Car {

    public BMWSedan() {
        brand = "BMW sedan";
    }
}

public class BMWSUV extends Car {

    public BMWSUV() {
        brand = "BMW SUV";
    }
}

接下来该是创建工厂的时候了,BMWFactory和Benz工厂:

public class BenzCarFactory extends CarFactory {

    public static final String SEDAN = "sedan";
    public static final String SUV = "suv";

    @Override
    protected Car createCar(String item) {
        Car car = null;
        if (SEDAN.equals(item)) {
            car = new BenzSedan();
        } else if (SUV.equals(item)) {
            car = new BenzSUV();
        }
        return car;
    }

}

public class BMWCarFactory extends CarFactory {

    public static final String SEDAN = "sedan";
    public static final String SUV = "suv";

    @Override
    protected Car createCar(String item) {
        Car car = null;
        if (SEDAN.equals(item)) {
            car = new BMWSedan();
        } else if (SUV.equals(item)) {
            car = new BMWSUV();
        }
        return car;
    }

}

是不是大功告成了? ,别急。接下来我们来看看怎么调用:

    public static void main(String[] args) {

        //奔驰工厂
        CarFactory carFactory = new BenzCarFactory();
        //创建奔驰轿车
        Car car = carFactory.newCar(BenzCarFactory.SEDAN);
        car.run();
        //创建奔驰SUV
        car = carFactory.newCar(BenzCarFactory.SUV);
        car.run();

        //宝马工厂
        carFactory = new BMWCarFactory();
        //创建奔驰轿车
        car = carFactory.newCar(BMWCarFactory.SEDAN);
        car.run();
        //创建奔驰SUV
        car = carFactory.newCar(BMWCarFactory.SUV);
        car.run();
    }

虽然和之前调用生成汽车的代码看起来,半斤八两,但这不是重点,重点是现在的代码结构可扩展性是之前if else方式无法比拟的。

接下来我们尝试之前说的扩展:

   1、增加一种Benz的车型SportsCar,我们只需要创建SportsCar和修改BenzFactory即可,不影响BMWFactory的任何东西,调用方式不变。

   2、增加一个汽车品牌,Lincoln,只需要创建LincolnFactory和Lincoln相关的Car类即可。

可能有些人会觉得这种方式和if else那种,除了代码结构清晰一点外也看不出什么优势,那是因为没有更深入的去研究,这里只能告诉你,慢慢深入去研究,然后再项目中用起来,你就懂了。

3、抽象工厂模式(GitHub源码

接下来就继续之前的需求,更深入的去了解工厂模式。新需求:

我们需要为不同的品牌不同型号的汽车自定义不同的配件,比如说:Body(车身),Chassis(底盘),Electrical(电力系统),Engine(引擎)

还想用if else的自己去厕所哭吧,分析思路:汽车品牌和车型我们之前已经处理过了可以继续沿用,现在的问题是新增的配件Parts的处理。同样首先还是抽象化,将配件抽象出来Body,Chassis,Electrical,Engine。然后根据品牌和车型生成不同的配件,这里唯一不同的地方是,配件可能是配套使用的,我们可以再增加一个配件的工厂 PartsFactory,保证一辆车上使用的是匹配的配件。接下来就看到底这个PartsFactory是怎样给汽车提供配件的了。代码如下:

public abstract class Car {

    protected String brand;
    protected Chassis chassis;
    protected Body body;
    protected Engine engine;
    protected Electrical electrical;

    public void prepare() {
        System.out.println("=== Start create a " + brand + " Car ===");
    }

    public void chassis() {
        System.out.println("Creating " + chassis.description());
    }

    public void body() {
        System.out.println("Creating " + body.description());
    }

    public void engine() {
        System.out.println("Creating " + engine.description());
    }

    public void electrical() {
        System.out.println("Creating " + electrical.description());
    }

    public void finish() {
        System.out.println("=== The birth of a new " + brand + "Car ===");
    }

    public void run() {
        System.out.println("Hello, I'm a new " + brand + " Car.");
        System.out.println();
    }

}

public interface PartsFactory {
    /**
     * 车身
     *
     * @return
     */
    Body body();

    /**
     * 电子系统
     *
     * @return
     */
    Electrical electrical();

    /**
     * 底盘
     *
     * @return
     */
    Chassis chassis();

    /**
     * 引擎
     *
     * @return
     */
    Engine engine();
}

public class BenzPartsFactory implements PartsFactory {
    @Override
    public Body body() {
        return new BenzBody();
    }

    @Override
    public Electrical electrical() {
        return new BenzElectrical();
    }

    @Override
    public Chassis chassis() {
        return new BenzChassis();
    }

    @Override
    public Engine engine() {
        return new BenzEngine();
    }
}

public class BMWPartsFactory implements PartsFactory {
    
    @Override
    public Body body() {
        return new BMWBody();
    }

    @Override
    public Electrical electrical() {
        return new BMWElectrical();
    }

    @Override
    public Chassis chassis() {
        return new BMWChassis();
    }

    @Override
    public Engine engine() {
        return new BMWEngine();
    }
}


以上代码中BenzBody等为继承抽象配件的实现类。BenzPartsFactory和BMWPartsFactory保证同一次使用的是一个系列的配件,  接下来我们需要修改CarFactory:

public class BMWCarFactory extends CarFactory {

    public static final String SEDAN = "sedan";
    public static final String SUV = "suv";

    @Override
    protected Car createCar(String item) {

        PartsFactory partsFactory;
        Car car = null;
        if (SUV.equals(item)) {
            partsFactory = new BMWPartsFactory();
            car = new BMWSUV(partsFactory);
        } else if (SEDAN.equals(item)) {
            //如果需要扩展,可继续创建相关的PartsFactory和Parts
        }
        return car;
    }
}

public class BMWCarFactory extends CarFactory {

    public static final String SEDAN = "sedan";
    public static final String SUV = "suv";

    @Override
    protected Car createCar(String item) {

        PartsFactory partsFactory;
        Car car = null;
        if (SUV.equals(item)) {
            partsFactory = new BMWPartsFactory();
            car = new BMWSUV(partsFactory);
        } else if (SEDAN.equals(item)) {
            //如果需要扩展,可继续创建相关的PartsFactory和Parts
        }
        return car;
    }
}

这就是抽象工厂,对于调用者来说,调用方式和之前工厂方法调用方法一样,但是内部实现方式却改变了,调用者根本不需要关心接口提供者是怎么实现的。

扩展:结构越复杂,扩展的难度就越大,如果我们需要添加新的汽车型号,需要添加对应的PartsFactory,Car和修改CarFactory

此处源码为部分源码,点击查看完整源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值