NipGeihou's blog NipGeihou's blog
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档

NipGeihou

我见青山多妩媚,料青山见我应如是
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档
  • 设计模式

    • 介绍与目的
    • 七大设计模式
    • 面向对象编程范式
    • 创造者模式
    • 创建者模式-单例模式
    • 创建者模式-工厂模式
      • 概念
      • 使用场景
      • 结构
      • 简单工厂模式
        • 小结
        • 源码应用
        • 扩展:简单工厂模式+配置文件(解除耦合)
      • 静态(简单)工厂模式
      • 工厂方法模式
        • 代码
        • 小结
        • 源码应用
      • 总结
    • 创建者模式-抽象工厂模式
    • 创建者模式-建造者模式
    • 创建者模式-原型模式
    • 结构型模式
    • 代理模式
    • 中介者模式
    • 命令模式
    • 责任链模式
    • 装饰模式
    • 策略模式
    • 适配器模式
    • 迭代器模式
    • 组合模式
    • 观察者模式
    • 外观模式
    • 备忘录模式
    • 访问者模式
    • 状态模式
    • 解释器模式
    • 享元模式
    • 桥接模式
    • 模板方法模式
  • 开发规范

  • 经验分享

  • 记录

  • 快速开始

  • 笔记

  • 面试题

  • 微服务

  • 踩过的坑

  • Java
  • 设计模式
NipGeihou
2022-09-01
目录

创建者模式-工厂模式

# 概念

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

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

来自 菜鸟教程 (opens new window)

# 使用场景

  • jdbc 连接数据库,硬件访问,降低对象的产生和销毁。

# 结构

简单工厂模式: 一个模块仅需要一个工厂类,没有必要把它产生出来,使用静态的方法。

多个工厂类: 每个人种(具体的产品类)都对应了一个创建者,每个创建者独立负责创建对应的产品对象,非常符合单一职责原则。

代替单例模式: 单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内存中生产一个对象。

延迟初始化: ProductFactory 负责产品类对象的创建工作,并且通过 prMap 变量产生一个缓存,对需要再次被重用的对象保留。

# 简单工厂模式

image-20220927224300859

简单工厂模式不属于 23 种设计模式,它是一种编码风格,他有点类似于策略模式,根据不同的参数返回不同的实现。

public class SimpleCoffeeFactory {
    public Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffee;
    }
}

# 小结

简单工程虽然不属于 23 种设计模式,但也很常见,它主要的思想是通过一个工厂(Factory)类来管理产品,对调用者隐藏了产品构造的细节,只管用(接口方法)就完事了。

优点

  • 解除耦合,降低客户端修改的可能性,更加容易扩展。

缺点

  • 违背了开闭原则,之后有新的产品需要改写 Factory 类代码

场景

在实际开发中,遇到需要获取多个不同型号设备的设备信息,而不同型号调用的 api 接口不一样,就会出现以下情况:

deviceList.forEach(device -> {
    DeviceInfo info = null;
    if("001".equals(device.getModel())){
        info = deviceAService.getInfo(device);
    } else if("002".equals(device.getModel()){
        info = deviceBService.getInfo(device);
    } 
    ...
})

使用简单工厂

DeviceInfoFactory deviceInfoFactory = new DeviceInfoFactory();
deviceList.forEach(device -> {
    DeviceInfo info = deviceInfoFactory.getDeviceInfo(device);
})

看似简洁了,不过是把上面的代码写去了 Factory 类,因此只能说这是一种编码风格,并没有设计可言。

# 源码应用

  • JDK:java.util.Calendar
  • JDK:java.text.NumberFormat
  • JDK:java.util.ResourceBundle

# 扩展:简单工厂模式 + 配置文件(解除耦合)

可以通过工厂模式 + 配置文件的方式解除工厂对象和产品对象的耦合。在工厂类中加载配置文件中的全类名,并创建对象进行存储,客户端如果需要对象,直接进行获取即可。

定义配置文件

american=com.itheima.pattern.factory.config_factory.AmericanCoffee
latte=com.itheima.pattern.factory.config_factory.LatteCoffee

改造工厂类

public class CoffeeFactory {

    private static Map<String,Coffee> map = new HashMap();

    static {
        Properties p = new Properties();
        InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            p.load(is);
            //遍历Properties集合对象
            Set<Object> keys = p.keySet();
            for (Object key : keys) {
                //根据键获取值(全类名)
                String className = p.getProperty((String) key);
                //获取字节码对象
                Class clazz = Class.forName(className);
                Coffee obj = (Coffee) clazz.newInstance();
                map.put((String)key,obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Coffee createCoffee(String name) {

        return map.get(name);
    }
}

# 静态(简单)工厂模式

这跟简单工厂模式一样,不属于 23 种设计模式,只是把简单工厂定义为静态的。

public class SimpleCoffeeFactory {

    public static Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffe;
    }
}

# 工厂方法模式

image-20220927231406337

# 代码

抽象工厂

public interface CoffeeFactory {

    Coffee createCoffee();
}

具体工厂

public class LatteCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}

public class AmericanCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}

咖啡店类

public class CoffeeStore {

    private CoffeeFactory factory;

    public CoffeeStore(CoffeeFactory factory) {
        this.factory = factory;
    }

    public Coffee orderCoffee(String type) {
        Coffee coffee = factory.createCoffee();
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}

# 小结

工厂方法模式相较于简单工厂多了 抽象工厂 角色,再把原本的工厂角色根据产品拆分出了多个产品工厂,每个产品工厂负责自己的产品生成,将来有新的产品,只需要添加新的产品工厂和产品类即可。

优点: 解决了简单工厂模式的缺点

缺点: 产品越多,类就越多,增加了系统的复杂度

# 源码应用

  • java.net.URLStreamHandlerFactory
点击查看
public interface URLStreamHandlerFactory {
    /**
     * Creates a new {@code URLStreamHandler} instance with the specified
     * protocol.
     *
     * @param   protocol   the protocol ("{@code ftp}",
     *                     "{@code http}", "{@code nntp}", etc.).
     * @return  a {@code URLStreamHandler} for the specific protocol, or {@code
     *          null} if this factory cannot create a handler for the specific
     *          protocol
     * @see     java.net.URLStreamHandler
     */
    URLStreamHandler createURLStreamHandler(String protocol);
}

  • javax.xml.bind.JAXBContext#createMarshaller
  • java.util.Collection#iterator
点击查看

image-20220928005234106

  • Collection 接口是抽象工厂类
  • ArrayList 是具体的工厂类
  • Iterator 接口是抽象商品类
  • ArrayList 类中的 Iter 内部类是具体的商品类

# 总结

工厂方法模式是我翻阅了最多资料去理解的一个模式,在咖啡店的例子中,咖啡店类需要传入具体的产品工厂,有人会有疑问:

那跟我直接 new 有什么区别,我都知道是什么产品工厂了,还不知道我是什么产品吗?

有这样的疑问(包括我自己)是因为没能把设计模式代入实际开发中,

如果这是一个 Spring 项目,再把 CoffeeStore 看作 Service,那么 CoffeeFactory 接口的具体实现则有 Spring 注入,还真不一定知道是什么产品工厂,在实际开发中,工厂模式会与策略模式配合使用,因此单看工厂模式是比较难理解的。

上次更新: 2024/03/11, 22:37:05
创建者模式-单例模式
创建者模式-抽象工厂模式

← 创建者模式-单例模式 创建者模式-抽象工厂模式→

最近更新
01
iSCSI服务搭建
05-10
02
磁盘管理与文件系统
05-02
03
网络测试 - iperf3
05-02
更多文章>
Theme by Vdoing | Copyright © 2018-2025 NipGeihou | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式