【设计模式】工厂模式(Factory Pattern)

2023-11-20

1. 概述

工厂模式(Factory Pattern)是最常用的设计模式之一,它属于创建类型的设计模式。它提供了一种创建对象的最佳方式,在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过一个共同的接口来指向新创建的对象。

工厂模式(Factory Pattern)是 3 种工厂模式的总称 —— 简单工厂模式(Simple Factory)工厂方法模式(Factory Method)抽象工厂模式(Abstract Factory)

这 3 种模式从上到下逐步抽象,并且具有一般性。用一下案例来理解工厂模式:

(1)在没有工厂的时代,如果用户需要一款宝马车,那么就需要用户自己去创建一款宝马车,即用户自己去执行创建一款宝马车所需要的一系列的复杂的操作,然后才能拿来用;
(2)简单工厂模式:后来出现了工厂,用户不再需要去创建宝马车,由工厂进行创建,即由工厂来执行创建宝马车的一些列复杂的操作,用户不用关心复杂的创建过程,用户想要什么车,直接通过工厂创建就可以了。比如,想要320i系列车,工厂就创建这个系列的车;
(3)工厂方法模式:为了满足不同用户的需求,宝马车推出了越来越多的车系以满足不同用户的需求,如320i系列、523i等等系列。原先一个工厂无法创建所有的宝马车系,于是又单独分出来多个具体的工厂,每个工厂创建一种车系,即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象,用户需要指定某个具体的工厂才能生产出他所需要的车。例如,客户需要宝马320i系列的车,那么他就需要执行生产宝马320i系列车的工厂生产一辆他所需要的车;
(4)抽象工厂模式:随着客户要求越来越高,宝马车必须配置空调,于是这个工厂开始生产宝马车和所需要的空调。用户只要提出他需要宝马320i空调车,宝马工厂就直接给他提供宝马320i空调车,而不用自己去创建宝马320i空调宝马车。

 

2. 简单工厂模式

简单工厂模式的核心是定义一个创建对象的接口,讲对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。

如果不使用工厂,用户将需要自己创建宝马车。

public class BMW320 {
    public BMW320() {
        System.out.println("制造-->BMW320");
    }
}

public class BMW523 {
    public BMW523() {
        System.out.println("制造-->BMW523");
    }
}

public class Customer {
    public static void main(String[] args) {
        // 不适用简单工厂模式时,用户需要宝马车,则需要自己去创建
        BMW320 bmw320 = new BMW320();
        BMW523 bmw523 = new BMW523();
    }
}

用户需要知道怎么创建一款车,这样客户和车就紧密耦合在一起了,为了降低耦合性,就出现了简单工厂模式,把创建宝马车的操作细节都放到了工厂里,而客户直接使用工厂的创建方法,传入想要的宝马车型号就行了,而不必去知道创建的细节。

UML类图

  • 工厂类角色:该模式的核心,用来创建产品,含有一定的商业逻辑和判断逻辑
  • 抽象产品角色:它一般是具体产品集成的父类或者实现的接口
  • 具体产品角色:工厂类所创建的对象就是次角色的实例,在JAVA中由一个具体的类实现

代码实现

产品类

public abstract class BMW {

    protected String type;

    public BMW() {
    }

    abstract public String getBMWType();
}

public class BMW320 extends BMW {
    public BMW320() {
        System.out.println("制造-->BMW320");
        type = "BMW320";
    }

    @Override
    public String getBMWType() {
        return type;
    }
}

public class BMW523 extends BMW {
    public BMW523() {
        System.out.println("制造-->BMW523");
        type = "BMW523";
    }

    @Override
    public String getBMWType() {
        return type;
    }
}

工厂类

public class BMWFactory {
    public BMW createBMW(String type) {
        switch (type) {
            case "320":
                return new BMW320();
            case "523":
                return new BMW523();
            default:
                break;
        }
        return null;
    }
}

Customer类

public class Customer {
    public static void main(String[] args) {
        BMWFactory bmwFactory = new BMWFactory();
        BMW bmw = bmwFactory.createBMW("320");
        System.out.println("BMW type: " + bmw.getBMWType());
    }
}

测试

 

简单工厂模式优缺点

优点
简单工厂模式提供专门的工厂类用于创建对象,实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需要知道具体产品类所对应的参数即可。通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

缺点
缺点在于不符合设计模式的 “开闭原则”(对扩展开放,对修改关闭),每次添加新的产品就需要修改工厂类。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要收到影响。

为了解决简单工厂模式的问题,出现了工厂方法模式。

 

3. 工厂方法模式

UML图

  • 抽象工厂 AbstractFactory:工厂方法模式的核心,是具体工厂角色必须实现的接口或者必须继承的父类,在JAVA中它由接口或者抽象类来实现;
  • 具体工厂 Factory:被应用程序调用以创建具体产品的对象,含有和具体业务逻辑有关的代码;
  • 抽象产品 AbstractProduct:是具体产品类继承的父类或实现的接口,在JAVA中一般由抽象类或者接口来实现;
  • 具体产品 Product:具体工厂角色所创建的对象就是此角色的实例。
     

代码实现

产品类

public abstract class BMW {

    protected String type;

    public BMW() {
    }

    abstract public String getBMWType();
}

public class BMW320 extends BMW {
    public BMW320() {
        System.out.println("制造-->BMW320");
        type = "BMW320";
    }

    @Override
    public String getBMWType() {
        return type;
    }
}

public class BMW523 extends BMW {
    public BMW523() {
        System.out.println("制造-->BMW523");
        type = "BMW523";
    }

    @Override
    public String getBMWType() {
        return type;
    }
}

工厂类

public interface BMWFactory {
    BMW createBMW();
}

public class BMW320Factory implements BMWFactory  {
    @Override
    public BMW createBMW() {
        System.out.println("BMW320 工厂生产 BMW320");
        return new BMW320();
    }
}

public class BMW523Factory implements BMWFactory  {
    @Override
    public BMW createBMW() {
        System.out.println("BMW523 工厂生产 BMW523");
        return new BMW523();
    }
}

Consumer类

public class Consumer {
    public static void main(String[] args) {
        // 用户指定具体的生产工厂
        BMWFactory bmwFactory= new BMW523Factory();
        // 由指定的工厂生产产品
        BMW bmw = bmwFactory.createBMW();
        System.out.println("BMW type: " + bmw.getBMWType());
    }
}

测试

 

工厂方法模式的优缺点

 

4. 抽象工厂模式

在工厂方法模式中,我们使用一个工厂创建一个产品,一个具体的工厂对应一个具体产品。但我们有时希望一个工厂能够提供多个产品对象,而不是单一的产品对象,这个时候就需要抽象工厂模式。

在了解抽象工厂模式之前,需要先理清楚 产品等级结构产品族 两个概念:

  • 产品等级结构
    产品等级结构指的是产品的继承结构,例如一个空调抽象类,它有海尔空调、隔离空调、美的空调等一系列的子类,那么这个空调抽象类和它的子类就构成了一个产品等级结构;

  • 产品族
    产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。例如,海尔工厂生产海尔空调、海尔冰箱,那么海尔空调、海尔冰箱就位于海尔产品族中。

抽象工厂主要用于创建相关对象的家族,当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用一个产品族中的对象;并且通过隔离具体类的生产,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

但该模式的缺点在于添加新的行为时比较麻烦,如果需要添加一个新的产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

 

UML图

  • 抽象工厂 AbstractFactory:定义了一个接口,这个接口包含了一组方法用来生产产品,所有的具体工厂都必须实现此接口;
  • 具体工厂 ConcreteFactory:用于生产不同的产品族,要创建一个产品,用户只需使用其中一个工厂进行获取,完全不需要实例化任何产品对象;
  • 抽象产品 AbstractProduct:这是一个产品家族,每一个具体工厂都能够生产一整组产品;
  • 具体产品 Product

 

代码实现

通过抽象工厂模式,我们可以实现以下的效果:比如宝马320系列使用空调型号A和发动机型号A,而宝马523系列使用空调型号B和发动机型号B,在为320系列生产相关配件时,就无需指定配件的型号,它会自动根据车型生产对应的配件型号A。

也就是说,当每个抽象产品都有多余一个具体子类的时候(空调有型号A和B两种,发动机也有型号A和B两种),工厂角色怎么知道实例化哪一个子类呢?抽象工厂模式提供两个具体工厂角色(宝马320系列工厂和宝马523系列工厂),分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化,每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。

产品类

// Engine
public abstract class AbstractEngine {
    /**
     * 引擎的型号
     */
    protected String type;
    abstract public String getType();
}

public class EngineA extends AbstractEngine {
    public EngineA() {
        this.type = "Engine A";
    }
    @Override
    public String getType() {
        return this.type;
    }
}

public class EngineB extends AbstractEngine {
    public EngineB() {
        this.type = "Engine B";
    }
    @Override
    public String getType() {
        return this.type;
    }
}


// AirConditioner
public abstract class AbstractAirConditioner {
    /**
     * 空调的型号
     */
    protected String type;
    abstract public String getType();
}

public class AirConditionerA extends AbstractAirConditioner {
    public AirConditionerA() {
        this.type = "AirConditioner A";
    }
    @Override
    public String getType() {
        return this.type;
    }
}

public class AirConditionerB extends AbstractAirConditioner {
    public AirConditionerB() {
        this.type = "AirConditioner B";
    }
    @Override
    public String getType() {
        return this.type;
    }
}

工厂类

public interface BMWFactory {
    AbstractEngine createEngine();
    AbstractAirConditioner createAirConditioner();
}

public class BMW320Factory implements BMWFactory {
    @Override
    public AbstractEngine createEngine() {
        System.out.println("制造 Engine A");
        return new EngineA();
    }
    @Override
    public AbstractAirConditioner createAirConditioner() {
        System.out.println("制造 AirConditioner A");
        return new AirConditionerA();
    }
}

public class BMW523Factory implements BMWFactory {
    @Override
    public AbstractEngine createEngine() {
        System.out.println("制造 Engine B");
        return new EngineB();
    }
    @Override
    public AbstractAirConditioner createAirConditioner() {
        System.out.println("制造 AirConditioner B");
        return new AirConditionerB();
    }
}

Consumer类

public class Consumer {
    public static void main(String[] args) {
        BMWFactory bmwFactory = new BMW523Factory();
        AbstractEngine engine = bmwFactory.createEngine();
        AbstractAirConditioner airConditioner = bmwFactory.createAirConditioner();
        System.out.println("Engine型号: " + engine.getType());
        System.out.println("AirConditioner型号: " + airConditioner.getType());
    }
}

测试

 

5. 工厂模式小结

工厂方法模式与抽象工厂模式的区别在于:

1)工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例;

2)抽象工厂模式拥有多个产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,同时每个具体工厂类可以创建多个具体产品类的实例。

 

参考文献

[1] https://blog.csdn.net/a745233700/article/details/120253639?spm=1001.2014.3001.5506

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【设计模式】工厂模式(Factory Pattern) 的相关文章

  • Java复习-25-单例设计模式

    单例设计模式 目的 使用场景 在实际开发下 会存在一种情况 某一种类在程序的整个生命周期中 只需要实例化一次就足够了 例如 系统数据类 由于操作系统只有一个 因此在程序初始化时该类只需要实例化一次 之后的系统数据更改都是在这一个实例化对象中
  • 23种设计模式之装饰模式

    装饰模式 一个简陋的房子 它可以让人在里面居住 为人遮风避雨 但如果给它进行装修 那么它的居住环境就更加宜人了 程序中的对象也与房子十分类似 首先有一个相当于 房子 的对象 然后经过不断装饰 不断对其增加功能 它就变成了使用功能更加强大的对
  • 常用设计模式总结

    设计模式的相关知识 很多书籍和博客中都有详细总结 本文总结的目的 1 将自己学习到的设计模式的知识按照自己的逻辑重新总结 方便查看和记忆 2 方便让自己对设计模式中常用的知识有一个系统的认知 设计模式 话设计模式 书中提到 24 种设计模式
  • 行为型模式-策略模式

    package per mjn pattern strategy 抽象策略类 public interface Strategy void show package per mjn pattern strategy 具体策略类 用来封装算法
  • C++设计模式(二)观察者模式

    1 观察者模式知识点 1 定义 定义对象间的一种一对多的依赖关系 当一个对象的状态发生改变的时候 所有依赖它的对象都得到通知并自动更新 2 动机 将一个系统分割成一系列相互协作的类有一个常见的副作用 需要维护相关对象间的一致性 我们不希望为
  • 设计模式之享元模式

    一 背景 在面向对象程序设计过程中 有时会面临要创建大量相同或相似对象实例的问题 创建那么多的对象将会耗费很多的系统资源 它是系统性能提高的一个瓶颈 例如 围棋和五子棋中的黑白棋子 图像中的坐标点或颜色 局域网中的路由器 交换机和集线器 教
  • java需会(转载)

    一 基础篇 1 1 Java基础 面向对象的特征 继承 封装和多态 final finally finalize 的区别 Exception Error 运行时异常与一般异常有何异同 请写出5种常见到的runtime exception i
  • 计算资源合并模式——云计算架构常用设计模式

    背景 云计算的解决方案中 最初设计可能有意遵循关注点分离的设计原则 把操作分解为独立的计算单元以便可以单独托管和部署 然而 虽然这种策略可以帮助简化解决方案的逻辑实现 但是在同一个应用程序中要部署大量的计算单元 这会增加运行时的托管成本 并
  • 设计模式学习之装饰器模式

    装饰器 Decorator 模式跟适配器 Adapter 模式一样 属于构建型设计模式 在学习适配器模式的时候说过 适配器模式的重点在复用能力 装饰器模式的重点在扩展能力 换言之 装饰器模式是先复用后扩展 这也导致了很多人跟适配器模式混淆
  • 第12课:生活中的构建模式——想要车还是庄园

    用程序来模拟生活 从剧情中思考构建模式 与工厂模式的区别 与组合模式的区别 构建模式的模型抽象 类图 基于升级版的实现 模型说明 应用场景 故事剧情 下周就要过年了 这是 Tony 工作后的第一个春节 还是在离家这么远的北京工作 所以肯定不
  • 每日一问:你想如何破坏单例模式?

    前言 1 单例是什么 单例模式 是一种创建型设计模式 目的是保证全局一个类只有一个实例对象 分为懒汉式和饿汉式 所谓懒汉式 类似于懒加载 需要的时候才会触发初始化实例对象 而饿汉式正好相反 项目启动 类加载的时候 就会创建初始化单例对象 1
  • 设计模式--提供者模式provider

    设计模式 C 提供者模式 Provider Pattern 介绍 为一个API进行定义和实现的分离 示例 有一个Message实体类 对它的操作有Insert 和Get 方法 持久化数据在SqlServer数据库中或Xml文件里 根据配置文
  • 单例模式的八种写法比较

    单例模式是最常用到的设计模式之一 熟悉设计模式的朋友对单例模式都不会陌生 一般介绍单例模式的书籍都会提到 饿汉式 和 懒汉式 这两种实现方式 但是除了这两种方式 本文还会介绍其他几种实现单例的方式 让我们来一起看看吧 简介 单例模式是一种常
  • 设计模式之享元模式

    享元模式 就是共享技术 对于系统中存在大量相同的对象 把他们抽取成一个对象放在缓存中进行使用 这样可以大大节省系统资源 例如 围棋棋盘上有两种棋子 一个是黑子 一个是白子 如果在下棋的时候每下一个棋子就要new一个棋子对象 那么就会有大量的
  • java-IO流(5)-IO流中的设计模式(装饰器模式和适配器模式)的介绍

    目录 1装饰器模式 1 1定义 1 2代码实现 1 3装饰器特点 1 4装饰器在IO流中的使用 2配适器模式 2 1Adapter适配器 2 2代码实例 2 3适配器特点 2 4适配器优缺点 2 5适配器在IO中的使用 3装饰器与适配器异同
  • [设计模式]模板方法模式(Template Method)

    1 意图 定义一个操作中的算法的骨架 而将一些步骤延迟到子类中 TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 2 动机 其实就是如意图所描述的 算法的骨架是一样的 就是有些特殊步骤不一样 就可以
  • 设计模式详解---策略模式

    1 策略模式简介 策略模式 Strategy Pattern 是一种行为型设计模式 用于在运行时根据不同的情境选择不同的算法或策略 该模式将算法封装成独立的类 使得它们可以相互替换 而且可以独立于客户端使用它们的方式 1 1 主要角色 上下
  • 设计模式(3)--对象结构(5)--外观

    1 意图 为子系统中的一组接口提供一个一致的界面 Facade模式定义了一个高层接口 这个接口使得 这一子系统更加容易使用 2 两种角色 子系统 Subsystem 外观 Facade 3 优点 3 1 对客户屏蔽了子系统组件 减少了客户处
  • 设计模式(三)-结构型模式(4)-组合模式

    一 为何需要组合模式 Composite 在代码设计中 有种情况是对象之间存在层次关系 即对象之间会存在父结点和子结点的关系 比如在文件管理系统中 所有文件和文件夹形成树状结构 文件夹目录里存在子文件夹和文件 文件夹属于枝结点 文件属于叶结
  • 【设计模式之美】 SOLID 原则之五:依赖反转原则:将代码执行流程交给框架

    文章目录 一 控制反转 IOC 二 依赖注入 DI 三 依赖注入框架 DI Framework 四 依赖反转原则 DIP 一 控制反转 IOC 通过一个例子来看一下 什么是控制反转 public class UserServiceTest

随机推荐

  • 设计模式之观察者模式(Observer)摘录

    23种GOF设计模式一般分为三大类 创建型模式 结构型模式 行为模式 创建型模式抽象了实例化过程 它们帮助一个系统独立于如何创建 组合和表示它的那些对象 一个类创建型模式使用继承改变被实例化的类 而一个对象创建型模式将实例化委托给另一个对象
  • 2021蓝桥杯模拟赛-跳跃

    题目 题目链接 题解 动态规划 算是比较基础的状态方程和状态定义 但是难点在于处理负权重的情况 代码 include
  • 通过微信小程序实现登录功能

    后端服务器可以在CSDN上开通 价格优惠 CSDN开发云 https img home csdnimg cn images 20220518054835 png https dev csdn net activity utm source
  • Java多线程(7):并发_线程同步_队列与锁(Synchronized)

    一 并发举例 线程不安全 1 两个人同时操作一张银行卡 如何保证线程安全 2 多个人同时购买一张火车票 谁能买到 二 并发特点 1 同一个对象 2 被多个线程操作 3 同时操作 三 如何保证线程安全 线程同步 队列 锁 1 使用队列的技术一
  • 走路步数怎么在屏幕上显示_华为走步步数不在屏幕上显示如何设置

    展开全部 1 打开手机的设置选项 找到 安全和隐私一栏 点击进入 2 进入后下拉屏幕 32313133353236313431303231363533e4b893e5b19e31333365666262找到并且选择 锁屏和密码 3 进入后在
  • idapython常用api记录7.0

    2019 02 13 idapython常用api记录 以下代码片段可以在ida的output窗口中测试用 需要引入相关的模块即可 import idaapi import idc import idautils 后续需要使用的程序代码指令
  • VUE 出现Access to XMLHttpRequest at 'http://192.168.88.228/login/Login?phone=19939306484&password=111'...

    报错如上图 解决办法首先打开 config gt index js 粘贴 如下图代码 https www baidu com 换成要访问的的api域名 注意只要域名就够了 不是整个api地址 代码 效果图 如下 更改完以后 还需要我们把sr
  • JDK1.8中HashMap的底层实现原理

    1 创建HashMap对象 public HashMap new一个hashmap 加载因子为默认的0 75f this loadFactor DEFAULT LOAD FACTOR all other fields defaulted 2
  • React中非受控组件-ref与受控组件理解

    内容 受控组件是通过 React 组件的状态来控制表单元素的值 非受控组件是通过手动操作 DOM 的方式来控制 此时 需要用到一个新的概念 ref ref 用来在 React 中获取 DOM 元素 非受控组件 ref ref的使用格式 步骤
  • list,tensor,numpy相互转化

    使用Pytorch的过程中 经常涉及到变量需要在list numpy和tensor之间自由转化 1 1 list 转 numpy ndarray np array list 1 2 numpy 转 list list ndarray tol
  • python3.7安装tkinter模块_Mac安装tkinter模块问题解决方法

    class Python lt Formula desc Interpreted interactive object oriented programming language homepage https www python org
  • ABAP--新语法--Open SQL--第四天-- From Table

    From Table Internal Table 在 ABAP 7 52 后 支持将内表作为数据源使用 内表作为数据源使用时 需要定义别名并使用转义符 该用法可以用来代替 FOR ALL ENTRIES IN 但FROM 语句中最多使用一
  • java脚本引擎Groovy实战

    前言 互联网时代随着业务的飞速发展 不仅产品迭代 更新的速度越来越快 个性化需求也是越来越多 如何快速的满足各种业务的个性化需求是我们要重点思考的问题 我们开发的系统如何才能做到热部署 不重启服务就能适应各种规则变化呢 实现业务和规则的解耦
  • APP环信集成 -JAVA后端

    环信的集成有两种方式 一种是先创建IM账号 然后在创建客服账号 在客服账号中新建渠道中 点击关联IM账号 这样创造出的关联以IM为主 收费要收取客服和IM两项费用 官方论坛里有给出这种方式的JAVA demo这里不过的赘述 这种场景适用于类
  • object.definepProperty使用方法,vue2双向绑定原理

    首先要介绍的是definepProperty的三个参数 object definepProperty 对象名 属性名 属性值 再者要介绍的就是属性值了 object definepProperty person age value 18 此
  • 【微服务架构设计】微服务不是魔术:处理超时

    微服务很重要 它们可以为我们的架构和团队带来一些相当大的胜利 但微服务也有很多成本 随着微服务 无服务器和其他分布式系统架构在行业中变得更加普遍 我们将它们的问题和解决它们的策略内化是至关重要的 在本文中 我们将研究网络边界可能引入的许多棘
  • std::chrono::steady_clock 实现精准休眠

    include
  • 【PAT】B1032 挖掘机技术哪家强 (20 分)_C语言实现

    1 挖掘机技术哪家强 20 分 为了用事实说明挖掘机技术到底哪家强 P A T PAT PAT 组织了一场挖掘机技能大赛 现请你根据比赛结果统计出技术最强的那个学校 输入格式 输入在第 1
  • 诡异至极的SQL Server推送数据到MQ日期早48小时的生产问题排查

    背景 应用迁移 即旧版应用下线 新版应用上线 停掉旧版应用里面的quartz任务 开启新版的xxl job调度任务 数据推送源头是SQL Server 目的地是MQ 问题爆出 今天iview的自动导出任务从老系统迁移到新系统 下午2点40
  • 【设计模式】工厂模式(Factory Pattern)

    1 概述 工厂模式 Factory Pattern 是最常用的设计模式之一 它属于创建类型的设计模式 它提供了一种创建对象的最佳方式 在工厂模式中 我们在创建对象时不会对客户端暴露创建逻辑 并且是通过一个共同的接口来指向新创建的对象 工厂模