设计模式之工厂(简单工厂模式、工厂方法模式、抽象工厂模式)

简单工厂模式、工厂方法模式、抽象工厂模式都属于创建型模式。创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。就像我们去商场购买商品时,不需要知道商品是怎么生产出来一样,因为它们由专门的厂商生产。

1 工厂设计模式

工厂模式分为简单工厂模式,工厂方法模式和抽象工厂模式,它们都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,目的是降低系统代码的耦合程度,并且增强了系统的扩展性。

1.1 简单工厂设计模式

简单工厂模式的最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会十分复杂。工厂设计模式适用于创建的过程十分复杂,但是需要的结果比较单一的情况。比如创建一辆车,我需要设置一堆的颜色、时速、外观类型、种类等等,创建过程十分复杂。

以造汽车为例子,如果我们需要各式各样的汽车,那么我们可以写一个造车工厂来实现汽车对象的创建。

package com.hj;
//首先创建一个汽车的接口
public interface Car {
    /*
    * 汽车启动方法
    * */
    void run();
}

接下来写一个奔驰类和宝马类来实现该接口

package com.hj;
//奔驰类
public class Benz implements Car {
    private String color = "red";
    private double speed = 128;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getSpeed() {
        return speed;
    }

    public void setSpeed(double speed) {
        this.speed = speed;
    }

    public void run() {
        System.out.println(this.color + "色的" + "奔驰启动了!" + "时速为:" + this.speed + "km/h");
    }
}
package com.hj;
//宝马类
public class BMW implements Car{
    //可能有一堆的成员变量
    private String color="red";
    private double speed=128;

    public double getSpeed() {
        return speed;
    }

    public void setSpeed(double speed) {
        this.speed = speed;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public void run(){
        System.out.println(this.color+"色的"+"宝马启动了!"+"时速为:"+this.speed+"km/h");

    }
}

然后按照一般的情况,java里创建一个宝马对象是这样的。比如我想要一辆红色的时速为128km/h的宝马汽车,我必须这么写:

import com.hj.BMW;
import com.hj.Car;
public class Client {
    public static void main(String[] args) {
        // 没有使用工厂方式的创建宝马方法,一堆的set方法,每个车都很复杂
        BMW car = new BMW();
        car.setColor("red");
        car.setSpeed(128);
        car.run();
    }
}

看起来好像不错,但是每一次都要去setColor和setSpeed。如果我要一百辆车,那我需要set一百次。而且这一百次的代码都是重复的。那么重复的代码我们可以抽象出来,制造一个造车工厂!

package com.hj;
// CarFactory类,用来造车
public class CarFactory {
    public Car carFactoryBuild(String type, String color, double speed) {
        if (type.equals("BMW")) {
            //如果传进来的是宝马,我就创建宝马
            BMW car = new BMW();
            car.setSpeed(speed);
            car.setColor(color);
            return car;
        } else if(type.equals("Benz")){
            Benz car=new Benz();
            car.setSpeed(speed);
            car.setColor(color);
            return car;
        }else return null;
    }
    public Car carFactoryBuild(String type, String color) {
        if (type.equals("BMW")) {
            //如果传进来的是宝马,我就创建宝马
            BMW car = new BMW();
            car.setColor(color);
            return car;
        }else if(type.equals("Benz")){
            Benz car=new Benz();
            car.setColor(color);
            return car;
        } else return null;
    }
    public Car carFactoryBuild(String type, double speed) {
        if (type.equals("BMW")) {
            //如果传进来的是宝马,我就创建宝马
            BMW car = new BMW();
            car.setSpeed(speed);
            return car;
        }else if(type.equals("Benz")){
            Benz car=new Benz();
            car.setSpeed(speed);
            return car;
        } else return null;
    }
    public Car carFactoryBuild(String type) {
        if (type.equals("BMW")) {
            //如果传进来的是宝马,我就创建宝马
            return new BMW();
        }else if(type.equals("Benz")){
            return new Benz();
        } else return null;
    }
}

好了,我们现在利用这个工厂去创建我们的汽车!

import com.hj.Car;
import com.hj.CarFactory;

public class Client {
    public static void main(String[] args) {
        // 创建一个造车工厂,这样就可以很快速地生成想要的车了
        CarFactory carFactory = new CarFactory();
        // 我就想要一辆宝马,参数随意
        Car car1 = carFactory.carFactoryBuild("BMW");
        car1.run();
        // 我就想要一辆绿色的时速为150km/h的宝马
        Car car2 = carFactory.carFactoryBuild("BMW", "green", 150);
        car2.run();
        // 甚至可以再来一辆黑色的奔驰
        Car car3 = carFactory.carFactoryBuild("Benz", "black");
        car3.run();
        // 来一辆黑色的时速150km/h的奔驰
        Car car4 = carFactory.carFactoryBuild("Benz", "black", 150);
        car4.run();
    }
}

可以看到,我们只需要创建一次工厂,后面就可以让工厂来为我们快速生成一个汽车对象了。有的人可能会觉得这样做反而更复杂了,那是因为这个汽车的属性才只有颜色和时速两个,若是还有轮胎材料、空调、联网类型、窗户样式、等等几百个参数。这样可以省去很多次set方法。

简易代码一览

//汽车工厂
public class CarFactory {
    public Car carFactoryBuild(String type, String color, double speed) {
        if ("BMW".equals(type)) {//小细节,如果type是null这样写不会报空指针异常,反过来就会报
            //如果传进来的是宝马,我就创建宝马
            BMW car = new BMW();
            car.setSpeed(speed);
            car.setColor(color);
            return car;
        } else if("Benz".equals(type)){
            Benz car=new Benz();
            car.setSpeed(speed);
            car.setColor(color);
            return car;
        }else return null;
    }
    public Car carFactoryBuild(String type, String color) {
        if ("BMW".equals(type)) {
            //如果传进来的是宝马,我就创建宝马
            BMW car = new BMW();
            car.setColor(color);
            return car;
        }else if("Benz".equals(type)){
            Benz car=new Benz();
            car.setColor(color);
            return car;
        } else return null;
    }
    public Car carFactoryBuild(String type, double speed) {
        if ("BMW".equals(type)) {
            //如果传进来的是宝马,我就创建宝马
            BMW car = new BMW();
            car.setSpeed(speed);
            return car;
        }else if("Benz".equals(type)){
            Benz car=new Benz();
            car.setSpeed(speed);
            return car;
        } else return null;
    }
    public Car carFactoryBuild(String type) {
        if ("BMW".equals(type)) {
            //如果传进来的是宝马,我就创建宝马
            return new BMW();
        }else if("Benz".equals(type)){
            return new Benz();
        } else return null;
    }
}

小结

优点
  1. 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确
  2. 客户端无需知道所创建具体产品的类名,只需知道参数即可
  3. 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类
缺点
  1. 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
  2. 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
  3. 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
应用场景

对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。总而言之,我们不希望在new的时候有一堆的复杂的set操作,我们希望把复杂的抽象出来,做成工厂。使用的时候可以用工厂去创建,这样就屏蔽了一些复杂的操作。

1.2 工厂方法模式

我们说过Java开发中要遵循开闭原则,如果将来有一天我想新增一种车,那么就必须修改我的简单工厂里的CarFactory类(上述提到的简单工厂模式的缺点),这太不灵活了,而且我已经写好的代码,根据开闭原则我不应该去修改他。为了解决这些问题,就出现了工厂方法模式。工厂方法模式是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

比如在上述的例子中,我们想在宝马和奔驰两种车的基础上,增加本田种类的车。如果在简单工厂模式中,我们只能在CarFactory类中添加一个else if来实现本田车类的判断。

那我们可以将CarFactory进一步抽象,将其变成接口,奔驰有奔驰的工厂、宝马有宝马的工厂、本田有本田的工厂。

首先写一个CarFactory2接口作为工厂的模板。

package com.hj;
public interface CarFactory2 {
    // 创建汽车的工厂的接口
    Car createCar(String color,double speed);
    Car createCar(String color);
    Car createCar(double speed);
    Car createCar();
}

然后分别实现宝马、奔驰、本田的造车工厂类

package com.hj;
//宝马工厂
public class BMWFactory implements CarFactory2 {
    @Override
    public Car createCar(String color, double speed) {
        BMW bmw = new BMW();
        bmw.setSpeed(speed);
        bmw.setColor(color);
        return bmw;
    }

    @Override
    public Car createCar(String color) {
        BMW bmw = new BMW();
        bmw.setColor(color);
        return bmw;
    }

    @Override
    public Car createCar(double speed) {
        BMW bmw = new BMW();
        bmw.setSpeed(speed);
        return bmw;
    }

    @Override
    public Car createCar() {
        return new BMW();
    }
}
package com.hj;
//奔驰工厂
public class BenzFactory implements CarFactory2{
    @Override
    public Car createCar(String color, double speed) {
        Benz benz = new Benz();
        benz.setSpeed(speed);
        benz.setColor(color);
        return benz;
    }

    @Override
    public Car createCar(String color) {
        Benz benz = new Benz();
        benz.setColor(color);
        return benz;
    }

    @Override
    public Car createCar(double speed) {
        Benz benz = new Benz();
        benz.setSpeed(speed);
        return benz;
    }

    @Override
    public Car createCar() {
        return new Benz();
    }
}
package com.hj;
//本田工厂
public class HondaFactory implements CarFactory2{
    @Override
    public Car createCar(String color, double speed) {
        Honda honda = new Honda();
        honda.setSpeed(speed);
        honda.setColor(color);
        return honda;
    }

    @Override
    public Car createCar(String color) {
        Honda honda = new Honda();
        honda.setColor(color);
        return honda;
    }

    @Override
    public Car createCar(double speed) {
        Honda honda = new Honda();
        honda.setSpeed(speed);
        return honda;
    }

    @Override
    public Car createCar() {
        return new Honda();
    }
}

客户文件里测试:

import com.hj.*;
public class Client2 {
    public static void main(String[] args) {
        //获得一辆红色的时速200的宝马
        CarFactory2 carFactoryBMW = new BMWFactory();
        Car bmwCar = carFactoryBMW.createCar("red", 200);
        bmwCar.run();
        //获得一辆绿色的奔驰
        CarFactory2 carFactoryBenz = new BenzFactory();
        Car benzCar = carFactoryBenz.createCar("green");
        benzCar.run();
        //获得一辆时速150的本田
        CarFactory2 carFactoryHonda = new HondaFactory();
        Car hondaCar = carFactoryHonda.createCar(150);
        hondaCar.run();
    }
}

简易代码一览

//工厂接口
public interface CarFactory2 {
    // 创建汽车的工厂的接口
    Car createCar();
}
//具体的工厂
public class BenzFactory implements CarFactory2{
    @Override
    public Car createCar() {
        return new Benz();
    }
}
public class BMWFactory implements CarFactory2 {
    @Override
    public Car createCar() {
        return new BMW();
    }
}
public class HondaFactory implements CarFactory2{
    public Car createCar() {
        return new Honda();
    }
}
//产品接口(大类)
public interface Car {
    void run();
}
public class Benz implements Car {
    private String color = "red";
    private double speed = 128;
    public void run() {
        System.out.println(this.color+"色的"+"奔驰启动了!"+"时速为:"+this.speed+"km/h");
    }
}
public class BMW implements Car{
    private String color="red";
    private double speed=128;
    @Override
    public void run(){
        System.out.println(this.color+"色的"+"宝马启动了!"+"时速为:"+this.speed+"km/h");
    }
}
public class Honda implements Car {
    private String color = "red";
    private double speed = 128;
    @Override
    public void run() {
        System.out.println(this.color+"颜色的本田启动了,"+"时速为"+this.speed+"km/h");
    }
}

小结

优点:
  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
  • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
  • 类的个数容易过多,增加复杂度
  • 增加了系统的抽象性和理解难度
  • 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
应用场景:
  • 客户只知道创建产品的工厂名,而不知道具体的产品名(client2.java文件里是不知道Benz类和BMW类的存在的,只出现了BenzFactory类和BMWFactory类)。如宝马工厂、奔驰工厂等。
  • 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
  • 客户不关心创建产品的细节,只关心产品的品牌,比如奔驰、宝马或者本田。

1.3 抽象工厂模式

可以看到在1.2工厂方法模式中,工厂只能生产汽车这一大类的产品。工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机等。但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调。抽象工厂模式可以打破工厂与产品(大类)一对一的关系,使得一个具体的工厂类可以生产多个大类的产品。比如我宝马工厂不再只能生产汽车,我还可以生产自行车。

也就是我们在工厂接口中多定义一个创建自行车方法。

package com.hj;
//自行车接口
public interface Bike {
    /*
     * 自行车启动方法
     * */
    void run();
}

宝马自行车实现类:

package com.hj;
//宝马自行车实现类
public class BMWBike implements Bike {
    private String color = "red";
    private double speed = 128;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getSpeed() {
        return speed;
    }

    public void setSpeed(double speed) {
        this.speed = speed;
    }

    @Override
    public void run() {
        System.out.println(this.color+"色的宝马自行车启动了,时速为"+this.speed+"km/h");
    }
}

抽象工厂的定义:

package com.hj;

public interface AbstractFactory {
    Car createCar(String color,double speed);
    Bike createBike(String color,double speed);
}

具体的宝马超级工厂:

package com.hj;
//宝马牌子工厂既可以生产汽车也可以生产自行车
public class BMWSuperFactory implements AbstractFactory {
    @Override
    public Car createCar(String color, double speed) {
        BMW bmw = new BMW();
        bmw.setSpeed(speed);
        bmw.setColor(color);
        return bmw;
    }

    @Override
    public Bike createBike(String color, double speed) {
        BMWBike bmwBike = new BMWBike();
        bmwBike.setColor(color);
        bmwBike.setSpeed(speed);
        return bmwBike;
    }
}

客户测试文件:

import com.hj.BMWSuperFactory;
import com.hj.Bike;
import com.hj.Car;

public class Client3 {
    public static void main(String[] args) {
        BMWSuperFactory bmwSuperFactory=new BMWSuperFactory();
        //想要一辆绿色的时速60的宝马自行车
        Bike bmwSuperFactoryBike = bmwSuperFactory.createBike("green", 60);
        bmwSuperFactoryBike.run();
        //想要一辆红色的时速150的宝马汽车
        Car bmwSuperFactoryCar = bmwSuperFactory.createCar("red", 150);
        bmwSuperFactoryCar.run();
    }
}

简易代码一览

//抽象工厂
interface AbstractFactory{
	Car createCar(String color,double speed);
	Bike createBike(String color,double speed);
}
//具体工厂
class BMWSuperFactory implements AbstractFactory{
        @Override
    public Car createCar(String color, double speed) {
        BMW bmw = new BMW();
        bmw.setSpeed(speed);
        bmw.setColor(color);
        return bmw;
    }

    @Override
    public Bike createBike(String color, double speed) {
        BMWBike bmwBike = new BMWBike();
        bmwBike.setColor(color);
        bmwBike.setSpeed(speed);
        return bmwBike;
    }
}
//产品大类——汽车
interface Car{
    void run();
}
public class BMW implements Car {
    @Override
    public void run(){
        System.out.println(this.color+"色的"+"宝马启动了!"+"时速为:"+this.speed+"km/h");
    }
}
//产品大类——自行车
interface Bike{
    void run();
}
public class BMWBike implements Bike {
    @Override
    public void run() {
        System.out.println(this.color+"色的宝马自行车启动了,时速为"+this.speed+"km/h");
    }
}

小结

抽象工厂模式通常适用于以下场景:

  1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  2. 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

抽象工厂其实就是工厂方法的扩展!当抽象工厂只有一种大类产品的时候,它就是工厂方法!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值