我所理解的设计模式系列·第2.1篇·三种工厂模式傻傻分不清楚(1)简单工厂模式

2022/01/08 设计模式 共 2694 字,约 8 分钟

本文主要介绍简单工厂模式(Simple Factory Pattern),它又叫静态工厂模式(Static Factory MethodPattern),它的定义是:“定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类”。

design-patttern-2

1. 模式介绍

工厂模式(Factory Design Pattern)是一种极为常用的用于创建对象的设计模式,在绝大部份开源框架中都有最佳实践,最为人所知的大概就是 Spring 的 BeanFactory 了。

工厂模式属于创建型模式,事实上它有三种不同的实现方式:简单工厂模式、工厂方法模式、抽象工厂模式

本文主要介绍简单工厂模式(Simple Factory Pattern),它又叫静态工厂模式(Static Factory MethodPattern),它的定义是:“定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类”

简单工厂模式并不属于 Gof23 种设计模式,只能算工厂模式的一种实现方法,因为它违背了设计模式六大原则的开放-封闭原则,因为每次添加一个产品类都需要在获取实例的方法中修改代码。

开放-封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

2. 应用场景

简单工厂模式,顾名思义适用于比较简单的场景:

  • 首先是需要创建的对象比较少,一只手掰的过来的那种
  • 其次是客户端不关心对象的创建过程,这是工厂模式的普遍应用场景

3. 类图

简单工厂模式中有三种角色:

  • 抽象产品(IProduct):描述了工厂创建的所有对象的抽象接口
  • 具体产品(Concrete Product):工厂创建的具体实例,实现了抽象产品接口
  • 简单工厂(Simple Factory):简单工厂模式的核心类,负责实现创建具体产品的逻辑。工厂类的创建具体产品的方法可以被外界直接调用。该方法一般是静态方法,所以简单工厂模式也被称为静态工厂模式。

这三种角色的类图如下所示:

design-patttern-2

4. 实现方式

下面就以一个具体的场景来展示简单工厂模式的实现方式。假设有一个用户现在想要用手机拍照,那么首先系统需要帮用户创建一个合适的手机,然后调用手机的通用能力——拍照来进行照相。

此时如果使用简单工厂来实现该需求,首先我们先来定义简单工厂模式种的抽象产品——手机的通用接口,也就是负责描述简单工厂创建的所有实例的公共接口:

public interface Phone {
    void takePhotos();
}

随后定义两个具体产品类,实现Phone公共接口:

public class IPhone implements Phone {
    @Override
    public void takePhotos() {
        System.out.println("IPhone...魔鬼前置");
    }
}

public class HuaWei implements Phone {
    @Override
    public void takePhotos() {
        System.out.println("华为...也能照亮你的美");
    }
}

最后,创建简单工厂模式种最核心的简单工厂类,它有一个静态方法,可根据不同的如餐获得不同的具体产品类:

public class PhoneFactory {

    /**
     * 根据传入的手机品牌获得手机实体类
     * 简单工厂:根据传入不同的参数创建不同的对象
     * @param brand 手机品牌
     * @return Phone
     */
    public static Phone getPhone(String brand) {
        Phone phone = null;
        if (brand.equalsIgnoreCase("huawei")) {
            phone = new HuaWei();
        } else if (brand.equalsIgnoreCase("iphone")) {
            phone = new IPhone();
        }
        return phone;
    }

    public static void main(String[] args) throws Exception {
        Phone phone = getPhone("huawei");
        phone.takePhotos();
    }
}

// 输出 
// 华为...也能照亮你的美

这样,我们就通过一个示例来实现了简单工厂模式。

5. 优缺点

简单工厂模式的优点:

  • 有良好的封装性,将客户端域创建具体产品的逻辑解耦。客户端如果需要创建一个具体产品,只要知道这个具体产品的别名(类名或指定字符串)就可以了,不需要知道创建的具体流程

简单工厂模式的缺点:

  • 拓展性较差,一旦有新的具体产品,需要修改简单工厂类创建具体产品方法的源代码才能生效,违反“开放-封闭原则”
  • 简单工厂模式中创建具体产品方法通常使用静态方法实现,这会让子类无法继承,有一定限制

6. 优化简单工厂模式

简单工厂模式有一个缺点是拓展性较差,违反“开放-封闭原则”。这里有一种优化此缺点的方案——使用反射机制优化创建具体对象方法,使得简单工厂不违反开闭原则,具体代码如下:

public class NewPhoneFactory {

    /**
     * 使用反射解决简单工厂每次增加新手机(产品类)都需要改代码的弊端,使得简单工厂不违反开闭原则
     *
     * @param clazz
     * @return Object
     */
    public static Object getPhoneClass(Class<? extends Phone> clazz) {
        try {
            return Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            System.out.println("创建具体产品类失败,具体原因为:");
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        // 传入的参数需要import或者类的全路径,可以使用配置文件的方式替代
        IPhone iPhone = (IPhone) getPhoneClass(IPhone.class);
        iPhone.takePhotos();
    }
}

// 输出
// IPhone...魔鬼前置

7. 小结

本文描述了简单工厂模式的定义、应用场景、实现方式、优缺点以及一种简单工厂模式的优化方案。

8. 参考资料

最后,本文收录于个人语雀知识库: 我所理解的后端技术,欢迎来访。

文档信息

Search

    Table of Contents