53

简单工厂、工厂方法和抽象工厂的区别

 4 years ago
source link: https://segmentfault.com/a/1190000021413329
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

工厂模式一般分为简单工厂、工厂方法和抽象工厂三种,看了很多资料,好多讲的都是云里雾里的。要么是概念太多,让人看得一脸懵逼,要么是举得例子不太恰当,看了更让人迷惑了。经过自己一番研究,通过一个简单的例子,终于搞明白了它们之间的区别。

下面以生产宝马、奔驰汽车的工厂为例,讲解它们之间的区别。

一、简单工厂模式

创建一个工厂类,根据传入的参数来决定创建哪个汽车类

//汽车接口
public interface Car {
    void getCar();
}
//宝马汽车类
public class BMWCar implements Car {
    @Override
    public void getCar() {
        System.out.println("这是宝马车");
    }
}
//奔驰汽车类
public class BenzCar implements Car {
    @Override
    public void getCar() {
        System.out.println("这是奔驰车");
    }
}
//工厂类,用于决定创建哪一个具体的汽车类
public class DefaultFactory {
    public Car produce(String name){
        if(name.equals("benz")){
            return new BenzCar();
        }else if(name.equals("bmw")){
            return new BMWCar();
        }
        return null;
    }
}

public class FTest {
    public static void main(String[] args) {
        DefaultFactory factory = new DefaultFactory();
        Car car = factory.produce("bmw");
        car.getCar(); //这是宝马车

        Car benz = factory.produce("benz");
        benz.getCar();  //这是奔驰车
    }
}

可以看到,在具体的工厂类DefaultFactory中,我们根据传入的name来决定创建哪一个汽车类。当需要创建宝马时,传入bmw,当需要创建奔驰时传入benz。思考一下,如果我需要创建一个大众汽车呢。是不是需要创建一个大众汽车类实现Car接口,还需要修改工厂类的produce方法,新增一个大众的分支。 再回忆一下,之前讲过的软件六大设计原则之一开闭原则。很明显,这违背了开闭原则(对修改是关闭的)。

于是,有了下边的工厂方法,可以保证遵循开闭原则。

二、工厂方法模式

工厂方法,相比于简单工厂,多了一个角色——工厂接口,负责定义生产汽车的公共接口,然后每个工厂实现类都去实现这个接口。

//工厂接口
public interface IFactory {
    Car produce();
}
//宝马生产工厂
public class BMWFactory implements IFactory{
    @Override
    public Car produce() {
        return new BMWCar();
    }
}
//奔驰生产工厂
public class BenzFactory implements IFactory {
    @Override
    public Car produce() {
        return new BenzCar();
    }
}

public class FacTest {
    public static void main(String[] args) {
        BMWFactory bmwFactory = new BMWFactory();
        bmwFactory.produce().getCar();   //这是宝马车

        BenzFactory benzFactory = new BenzFactory();
        benzFactory.produce().getCar();  //这是奔驰车
    }
}

可以看到,我把之前的一个工厂,拆分为两个工厂。当具体需要哪个汽车的时候,就去实例化它对应的工厂。这样,当再需要大众车的时候,我只需要添加一个大众车的类和大众车对应的工厂实现类去实现IFactory接口就可以了。不需要修改原来的代码,这就符合开闭原则了。

三、 抽象工厂模式

初识抽象工厂的同学,总是很迷惑它和工厂方法有什么区别,不就是在工厂实现类里多了几个方法吗。其实,抽象工厂是对工厂方法的升级,用于创建一组相互关联或相互依赖的对象。

在此需要了解一下产品等级和产品族的关系。假如有一个汽车制造商,它只生产低配版的汽车产品(至于为什么,我猜是低配版更亲民,销量更高吧,哈哈),其中就包括低配宝马和低配奔驰。还有一个汽车制造商只生产高配版的汽车(没什么原因,就是钱多任性,高端大气上档次),如高配宝马和高配奔驰。

我们就把高配制造商或者低配制造商称为一个产品族。而其中的低配宝马和低配奔驰属于同一个产品等级,高配宝马和高配奔驰属于同一个产品等级。

画一张图来理解一下它们的概念,横向是三个产品族,纵向是两个产品等级。

ArUbMfY.png!web

代码如下:

//工厂接口,包含两个方法,创建宝马和创建奔驰
public interface IFactory {
    Car produceBMW();
    Car produceBenz();
}
//-------- 高配车和工厂实现类 -------//
public class HighBMW implements Car {
    @Override
    public void getCar() {
        System.out.println("高配宝马车");
    }
}
public class HighBenz implements Car {
    @Override
    public void getCar() {
        System.out.println("高配奔驰车");
    }
}
public class HighFactory implements IFactory {
    @Override
    public Car produceBMW() {
        return new HighBMW();
    }

    @Override
    public Car produceBenz() {
        return new HighBenz();
    }
}
//-------- 低配车和工厂实现类 ----------//
public class LowBMW implements Car {
    @Override
    public void getCar() {
        System.out.println("低配宝马车");
    }
}
public class LowBenz implements Car {
    @Override
    public void getCar() {
        System.out.printf("低配奔驰车");
    }
}
public class LowFactory implements IFactory {
    @Override
    public Car produceBMW() {
        return new LowBMW();
    }

    @Override
    public Car produceBenz() {
        return new LowBenz();
    }
}

public class AbsTest {
    public static void main(String[] args) {
        HighFactory highFactory = new HighFactory();
        highFactory.produceBMW().getCar();  //高配宝马车
        highFactory.produceBenz().getCar();  //高配奔驰车

        LowFactory lowFactory = new LowFactory();
        lowFactory.produceBMW().getCar();  //低配宝马车
        lowFactory.produceBenz().getCar();  //低配奔驰车
    }
}

乍一看,抽象工厂和工厂方法特别的相似,其实这里边就是多了一个产品族的概念,它强调一个产品族的对象应该放到同一个工厂类里边。比如,我再需要一个中配版或者豪华版的汽车制造商,只需要实现它的具体工厂类和相应的各同等级的汽车类。

总结:

  1. 简单工厂顾明思议,实现比较简单,只需要传入一个特定参数即可,不用知道具体的工厂实现类名,缺点就是违背了开闭原则。
  2. 工厂方法和抽象工厂,遵守开闭原则,解耦了类关系。但是,扩展比较复杂,需要增加一系列的类。
  3. 需要注意,工厂方法和抽象工厂的区别就在于,抽象工厂关注于某一个产品族,当产品对象之间是有关联关系的一个产品族时用这种方式,而工厂方法没有产品族的概念。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK