设计模式深入解析----工厂模式|8月更文挑战

285 阅读5分钟

这是我参与8月更文挑战的第1天,活动详情查看: 8月更文挑战

借 8 月更文挑战来督促自己,感谢掘金!

工厂模式分为三种,分别是简单工厂、工厂方法和抽象工厂,下面分别介绍。

简单工厂

简单工厂模式其实并不是一种设计模式,而是我们的一种编码习惯。下面先看简单工厂模式的 UML 图:

截屏2021-08-01 22.52.05.png

下面来举例说明什么是简单工厂模式。

现在有一个食物这样的接口,关于食物的具体实现有面条和汉堡。有一个食物工厂,是用来生产食物的,根据传入的不同参数生产不同的食物。

食物接口:

/**
 * @Author: JonesYong
 * @Data: 2021-08-01
 * @Description:
 */
public interface Food {
    void createFood();
}

面条和汉堡:

/**
 * @Author: JonesYong
 * @Data: 2021-08-01
 * @Description:
 */
public class Noodle implements Food {

    @Override
    public void createFood() {
        System.out.println("noodle was created.");
    }
}
/**
 * @Author: JonesYong
 * @Data: 2021-08-01
 * @Description:
 */
public class Hamburger implements Food {


    @Override
    public void createFood() {
        System.out.println("Hamburger was created.");
    }
}

下面来看食物工厂:

/**
 * @Author: JonesYong
 * @Data: 2021-08-01
 * @Description:
 */
public class SimpleFactory {
    public static Food getFoodInstance(String type) {
        Food food = null;
        switch (type) {
            case "Noodle":
                food = new Noodle();
                break;
            case "Hamburger":
                food = new Hamburger();
                break;
        }
        return food;
    }
}

像这样,根据传入的不同的参数生产不同的对象,避免无用对象的创建,我们称之为简单工厂模式。但是简单工厂有着很明显的缺点,比如这个时候又多出来一种食物,我们就得去修改食物工厂的代码,这样就违反了开闭原则。

工厂方法

就像上面说的那样,简单工厂模式虽然使用简单,但是确违反了开闭原则。如果使用工厂方法就得到了很好的解决,下面请看工厂方法的 UML:

截屏2021-08-02 02.22.46.png

之前说的简单工厂的模式违反了开闭原则,我们每次增加一种食物,都需要去食物工厂里修改对应的代码!

那么工厂方法又是如何避免这种情况发生的了?仔细看 UML 图可以发现,每一种食物都对应一种食物工厂,如果要新增加一种食物的话,我们需要创建一个工厂出来,用来生产对应的食物。 代码细节如下:

这是一个食物的接口抽象:

/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public interface FoodFactory {
    Food createFood();
}

具体有两个实现类:

/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public class NoodleFactory implements FoodFactory {
    @Override
    public Food createFood() {
        return new Noodle();
    }
}
/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public class HamburgerFactory implements FoodFactory{
    @Override
    public Food createFood() {
        return new Hamburger();
    }
}

想这样,我们需要增加某一个功能的时候,只需要重新定一个具体事物,然后我们客户端再重新增加相对应的工厂就行了。这是不违反开闭原则的,并且解决了客户端和服务的耦合性!

写着写着,好像发现了那你不对劲。思考一下,如果我们每次增加一种食物,就需要增加一个工厂。如果食物越来越多,岂不是额外的工厂类也越来越多,这样就会产生类爆炸的情况!

这个时候抽象工厂出现了,它巧妙地解决了类爆炸的情况。

抽象工厂

先看一下抽象工厂的 UML :

截屏2021-08-01 22.52.49.png

其实抽象工厂挺不好理解的,下面来举一个例子。

现在业务上不仅生产食物,还需要生产饮料。增加了一个饮料接口如下:

/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public interface Drink {
    void createDrink();
}

它的两个实现类如下:

/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public class Milk implements Drink {
    @Override
    public void createDrink() {
        System.out.println("Milk was created.");
    }
}
/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public class Cola implements Drink {
    @Override
    public void createDrink() {
        System.out.println("Cola was created.");
    }
}

结合具体的情景,我们这是一个食品工厂,食品工厂就已经包含食物和饮料了,也不能在 FoodFactory 之外重新创建一个DrinkFactory(公司拒绝搞分裂)。那现在怎么办了?在FoodFactory之内创建一个DrinkFactory也不太合适,毕竟和NoodleFactoryHamburgerleFactory还是有一定区别的。

那可怎么办呢?我在想,是不是可以把这些个饮料和具体的食物搭配在一起进行出售了?其实这和公司的业务架构有点类似,每个子业务交给独立的大部门完成,这个大部门又可以分成前端、后端、算法,众多的子业务组成了整个公司的业务线。

类比如下: 整个公司的业务相当于FoodFactory,在 FoodFactory下面有许多的大部门(子业务)KFCFactoryChinaFactory等,这些个大部门又可以分前端后端啥的(生产不同的食物、饮料)。

代码细节如下:

工厂的接口,每一个食物工厂都需要实现这个接口:

/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public interface FoodFactory {
    Food createFood();

    Drink createDrink();
}

食物工厂有两个实现类,分别用来创建不同的食物:

/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public class ChinaFactory implements FoodFactory {

    @Override
    public Food createFood() {
        return new Noodle();
    }

    @Override
    public Drink createDrink() {
        return new Milk();
    }
}
/**
 * @Author: JonesYong
 * @Data: 2021-08-02
 * @Description:
 */
public class KFCFactory implements FoodFactory {

    @Override
    public Food createFood() {
        return new Hamburger();
    }

    @Override
    public Drink createDrink() {
        return new Cola();
    }
}

抽象工厂貌似解决了类爆炸的问题,但是仔细想一下还是存在问题的。如果这个时候,我们的需求又增加了,还需要生产冰淇淋,这势必会修改原来的 Factory 对应的功能,违反了开闭原则。

好了,工厂模式的介绍到此结束了。

另外,由于水平有限,有错误的地方在所难免,未免误导他人,欢迎大佬指正!码字不易,感谢大家的点赞关注!🙏