【设计模式】工厂模式详解

news2025/1/12 21:08:22

1.简介

工厂模式是一种创建型设计模式,通过提供一个接口或抽象类来创建对象,而不是直接实例化对象。工厂模式的主要思想是将对象的创建与使用分离,使得创建对象的过程更加灵活和可扩展。

工厂模式主要包括以下角色:

  • 抽象工厂(Abstract Factory):定义了一个创建产品对象的接口,可以包含多个方法来创建不同类型的产品。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责实例化具体的产品对象。
  • 抽象产品(Abstract Product):定义了产品的接口或抽象类,是工厂方法和抽象工厂模式中的基础。
  • 具体产品(Concrete Product):实现抽象产品接口,具体定义产品的功能和行为。

2.简单工厂模式

简单工厂模式(Simple Factory Pattern):由一个工厂类根据传入的参数决定创建哪一种产品类的实例。它通常包含一个静态方法,这个方法根据参数创建相应的对象。

定义一个简单的例子:电脑有很多品牌,如惠普电脑、联想电脑,如果需要创建这两个对象时,主动new出来,使用了简单工厂模式后,可以把创建的动作交给工厂类,只需要指定参数即可获取对应的对象。

实现方法

  1. 编写产品类

首先创建一个Computer接口,不同的产品实现这一接口

// 定义抽象产品接口
public interface Computer {
    void compute();
}

// 定义具体产品,实现该接口
public class HPComputer implements Computer{
    @Override
    public void compute() {
        System.out.println("我是惠普电脑");
    }
}

public class LenovoComputer implements Computer{
    @Override
    public void compute() {
        System.out.println("我是联想电脑");
    }
}
  1. 编写工厂类

简单工厂模式不存在抽象工厂,只需编写一个工厂类即可。

// 根据传入的参数创建对应产品
public class SimpleFactory {
    public static Computer createProduct(String type) {
        if (type.equals("HP")) {
            return new HPComputer();
        } else if (type.equals("Lenovo")) {
            return new LenovoComputer();
        } else {
            throw new IllegalArgumentException("该类型无法被生产");
        }
    }
}
  1. 测试类使用工厂创建产品
public class Main {
    public static void main(String[] args) {
        // 创建HP电脑
        Computer hp = SimpleFactory.createProduct("HP");
        // 创建Lenovo电脑
        Computer lenovo = SimpleFactory.createProduct("Lenovo");
        hp.compute();
        lenovo.compute();
    }
}

输出结果如下:

小结

简单工厂模式虽然实现比较简单,但是工厂类的职责过重,增加新的产品类型需要修改工厂类,违背了开闭原则。

开闭原则: 软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。

对扩展开放(Open for extension):软件实体应该允许在不改变其现有代码的情况下,通过增加新功能来对其进行扩展。也就是说,当软件的需求发生变化时,我们应该能够通过添加新代码来满足这些需求,而不需要修改已有的代码。

对修改关闭(Closed for modification):一旦软件实体被开发完成并投入使用,其源代码就不应该再被修改。这可以防止对现有功能的破坏,减少引入新的错误的风险,并使软件更加稳定和可维护。

3.工厂方法模式

工厂方法模式(Factory Method Pattern):定义一个创建对象的接口,但由子类决定实例化哪个类。工厂方法将对象的创建推迟到子类。

实现方法

  1. 编写产品类
// 定义抽象产品接口
public interface Computer {
    void compute();
}

// 定义具体产品,实现该接口
public class HPComputer implements Computer{
    @Override
    public void compute() {
        System.out.println("我是惠普电脑");
    }
}

public class LenovoComputer implements Computer{
    @Override
    public void compute() {
        System.out.println("我是联想电脑");
    }
}
  1. 编写工厂类

需要定义一个抽象工厂,然后由具体工厂创建对应的产品。

// 定义抽象工厂
public interface ComputerFactory {
    Computer createComputer();
}

// 定义HP工厂
public class HPComputerFactory implements ComputerFactory{
    @Override
    public Computer createComputer() {
        return new HPComputer();
    }
}

// 定义Lenovo工厂
public class LenovoComputerFactory implements ComputerFactory{
    @Override
    public Computer createComputer() {
        return new LenovoComputer();
    }
}
  1. 测试类使用不同的具体工厂创建产品
public class Main {
    public static void main(String[] args) {
        // 创建HP电脑
        HPComputerFactory hpFactory = new HPComputerFactory();
        Computer hpComputer = hpFactory.createComputer();
        hpComputer.compute();

        // 创建Lenovo电脑
        LenovoComputerFactory lenovoFactory = new LenovoComputerFactory();
        Computer lenovoComputer = lenovoFactory.createComputer();
        lenovoComputer.compute();
    }
}

输出结果如下:

小结

优点:

  • 遵循开闭原则,新增产品时不需要修改现有系统代码,只需要添加新的具体工厂和具体产品类。
  • 更符合单一职责原则,每个具体工厂类只负责创建一种产品。

缺点:

  • 增加了系统复杂度,需要增加额外的类和接口。

4.抽象工厂模式

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。适用于产品族的场景,即多个产品等级结构中相关的产品需要一起创建和使用。

产品等级结构: 指产品的继承结构,例如一个电脑抽象类,它有HP电脑、Lenovo电脑等实现类,那么这个电脑抽象类和他的实现类就构成了一个产品等级结构。

产品族: 产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。比如,Lenovo除了生产电脑还可以生产打印机等其他产品。

实现方法

  1. 编写产品类
// 定义电脑抽象产品接口
public interface Computer {
    void compute();
}

// 定义电脑具体产品,实现该接口
public class HPComputer implements Computer{
    @Override
    public void compute() {
        System.out.println("我是惠普电脑");
    }
}

public class LenovoComputer implements Computer{
    @Override
    public void compute() {
        System.out.println("我是联想电脑");
    }
}

// 定义打印机抽象产品接口
public interface Printer {
    void print();
}

// 定义打印机具体产品,实现该接口
public class HPPrinter implements Printer {
    @Override
    public void print() {
        System.out.println("我是惠普打印机");
    }
}

public class LenovoPrinter implements Printer{
    @Override
    public void print() {
        System.out.println("我是联想打印机");
    }
}
  1. 编写工厂类

定义一个抽象工厂,该工厂可以创建多个产品。

// 定义抽象工厂
public interface AbstractFactory {
    Computer createComputer();

    Printer createPrinter();
}

// 定义HP工厂
public class HPFactory implements AbstractFactory{
    @Override
    public Computer createComputer() {
        return new HPComputer();
    }

    @Override
    public Printer createPrinter() {
        return new HPPrinter();
    }
}

// 定义Lenovo工厂
public class LenovoFactory implements AbstractFactory {
    @Override
    public Computer createComputer() {
        return new LenovoComputer();
    }

    @Override
    public Printer createPrinter() {
        return new LenovoPrinter();
    }
}
  1. 测试类使用不同的具体工厂创建产品
public class Main {
    public static void main(String[] args) {
        HPFactory hpFactory = new HPFactory();
        Computer hpComputer = hpFactory.createComputer();
        Printer hpPrinter = hpFactory.createPrinter();

        hpComputer.compute();
        hpPrinter.print();

        System.out.println("===============");

        LenovoFactory lenovoFactory = new LenovoFactory();
        Computer lenovoComputer = lenovoFactory.createComputer();
        Printer lenovoPrinter = lenovoFactory.createPrinter();
        lenovoComputer.compute();
        lenovoPrinter.print();
    }
}

输出结果如下:

小结

优点:

  • 符合开闭原则,新增产品族时无需修改现有系统代码。
  • 符合单一职责原则,每个具体工厂类只负责创建一类产品族。
  • 保证产品族的一致性,同一个工厂创建的产品是属于同一个产品族的。

缺点:

  • 增加了系统的复杂度。修改产品族时,需要修改所有具体工厂类,扩展性稍差。

5.总结

适用场景:

  • 简单工厂模式:适用于产品种类较少,客户端只需根据参数获得具体产品的简单场景。适合产品种类不经常变化的场合。

  • 工厂方法模式:适用于产品种类较多,每个产品有相应的具体工厂类。适合需要扩展新产品,且不希望修改现有代码的场合。

  • 抽象工厂模式:适用于产品族较多,每个产品族中包含多个相关产品。适合创建一系列相关或相互依赖的产品,且希望统一管理产品族的场合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1959445.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java 字符串a+b到底生成几个对象?

我们知道,java内存模型是堆栈元空间(也叫方法区,它是在内存中的)。 字符串常量池保存在堆里面。为了节约空间,如果常量池里面有,就不需要创建对象,只需要返回常量池里面的引用;如果…

c#实际开发长到的知识

个人建议先把rotion的库导入进来再操作,具体需要导入的库有,helper库包含了modbus通讯封装好的模块,而mvvm则可以用来做设计mvvm模块,你可以使用里面封装好的实现方法,用起来特别简单更容易实现其中的操作,但是我担心那天被卡脖子了啊啊啊,要是我罗工把库下架了那不是死…

圈子论坛小程序搭建,文章源码链接上传功能社交需求带支付功能

论坛小程序技术栈 前端:uni-app,vue3 后端:PHP,thinkphp8 数据库设计: 设计数据库结构,存储用户数据、帖子数据等。 数据库系统:MySQL5.7 功能开发: 明确小程序的功能需求:浏览、发帖、评…

ChemLLM:化学领域的大模型

人工智能咨询培训老师叶梓 转载标明出处 在化学这一特定学科的应用上,一直缺乏专门的对话模型。化学数据和科学知识通常存储在结构化的数据库中,这给直接使用这些数据训练语言模型带来了挑战。为了解决这一问题,来自上海人工智能实验室的研究…

RabbitMQ高级篇(如何保证消息的可靠性、如何确保业务的幂等性、延迟消息的概念、延迟消息的应用)

文章目录 1. 消息丢失的情况2. 生产者的可靠性2.1 生产者重连2.2 生产者确认2.3 生产者确认机制的代码实现2.4 如何看待和处理生产者的确认信息 3. 消息代理(RabbitMQ)的可靠性3.1 数据持久化3.2 LazyQueue( 3.12 版本后所有队列都是 Lazy Qu…

《七日世界》游玩感想

《七日世界》是一款最近新出的引人入胜的游戏,它以独特的故事情节和精美的画面设计吸引了许多玩家的关注。在这款游戏中,玩家需要在七天的时间里探索一个神秘的幽灵世界,解开其中的谜题,救出被困的灵魂。 首先,让我来聊…

1996-2023年上市公司绿色并购数据(含原始数据+处理代码+计算结果)

1996-2023年上市公司绿色并购数据(含原始数据处理代码计算结果) 1、时间:1996-2023年 2、指标:股票代码、首次公告日期、年份、买方、卖方、标的方、交易概述、标的物名称、标的物说明、买方经营范围、卖方经营范围、标的方经营…

28.jdk源码阅读之CopyOnWriteArraySet

1. 写在前面 CopyOnWriteArraySet 是 Java 中一个线程安全的 Set 实现,它的底层是基于 CopyOnWriteArrayList 实现的。这种数据结构在并发编程中非常有用,因为它在写操作时会创建一个新的数组副本,从而避免了并发修改问题。不知道大家对它的底…

angular入门基础教程(五)父子组件的数据通信

组件之间的通信是我们业务开发中少不了的,先了解下父子组件的通信 父组件传数据给子组件 前面,我们学会会动态属性的绑定,所以在父组件中给子组件绑定属性,在子组件中就可以使用这个属性了。 父组件中声明然后赋值 export class AppCompon…

C语言 | Leetcode C语言题解之第304题二维区域和检索-矩阵不可变

题目: 题解: typedef struct {int** sums;int sumsSize; } NumMatrix;NumMatrix* numMatrixCreate(int** matrix, int matrixSize, int* matrixColSize) {NumMatrix* ret malloc(sizeof(NumMatrix));ret->sums malloc(sizeof(int*) * (matrixSize …

图论:721. 账户合并(并查集扩展)

文章目录 1、题目链接2、题目描述3、并查集思路3.1、按秩合并3.2、常用并查集代码 4、题目解析 1、题目链接 721. 账户合并 2、题目描述 3、并查集思路 并查集可以在很短的时间内合并不同的集合。它的思想为,一开始将不同单元单独作为一个结点,然后按…

【Qt】修改窗口的标题和图标

以下操作仅对顶层 widget(独⽴窗口),有效。 修改窗口的标题 一.windowTitle属性 1.概念 是一种在用户界面中显示窗口的标题的属性。它可以用来设置窗口的标题栏文本。 2.API API说明windowTitle()获取到控件的窗⼝标题.setWindowTitle(const QString& title)设置控件的…

线性回归和逻辑回归揭示数据的隐藏模式:理论与实践全解析

机器学习之线性回归和逻辑回归 1. 简介1.1 机器学习概述1.2 监督学习的定义与重要性1.3 线性回归和逻辑回归在监督学习中的作用1.3.1 线性回归1.3.2 逻辑回归 2. 线性回归(Linear Regression)2.1 定义与目标2.1.1 回归问题的定义2.1.2 预测连续目标变量 …

Redis持久化之RDB和AOF详解

持久化是确保 Redis 数据在服务器重启或崩溃时不丢失的关键功能。由于 Redis 是基于内存的数据库,如果不进行持久化,所有数据都存在于内存中,一旦服务器进程退出,内存中的数据就会丢失。持久化机制可以将 Redis 的数据库状态保存到…

Qt 学习第三天:加一个按钮

本章心得&#xff1a; 这个章节有点像写前端的味道了&#xff0c;设置按钮大小&#xff0c;按钮位置&#xff0c;窗口大小......代码全在widget.cpp上写的 #include "widget.h" #include "ui_widget.h" #include <QPushButton>Widget::Widget(QWid…

C++初级学习:⼊⻔基础

本文内容&#xff1a; 1.C参考⽂档&#xff1a;2.C第一个程序3.命名空间3.1namespace的价值3.2namespace的定义3.3命名空间的使用 4.C输⼊&输出5.缺省参数6.函数重载 1.C参考⽂档&#xff1a; https://legacy.cplusplus.com/reference/ https://zh.cppreference.com/w/cp…

实战:Zookeeper 简介和单点部署ZooKeeper

Zookeeper 简介 ZooKeeper是一个开源的分布式协调服务&#xff0c;它是Apache软件基金会下的一个项目&#xff0c;旨在解决分布式系统中的协调和管理问题。以下是ZooKeeper的详细简介&#xff1a; 一、基本定义 ZooKeeper是一个分布式的、开放源码的分布式应用程序协调服务&a…

添加索引导致微服务异常

一、现象 某app部分功能不可用&#xff0c;提示“连接服务器超时&#xff0c;请稍后尝试”。 二、分析 1、分析发现数据库存在大量的TM争用。 2、继续分析发现存在TM行锁的阻塞会话主要是以下几个&#xff1a; 3、查看其阻塞源头是1940 4、而1940进程在这个时间段是在跑新增索…

逆矩阵、秩

在数学的广阔天地中&#xff0c;线性代数扮演着至关重要的角色。它不仅是现代科学和工程学的基石&#xff0c;也是理解复杂数据结构的关键。本文将深入探讨线性代数中的几个核心概念&#xff1a;逆矩阵、秩、列空间和零空间&#xff0c;通过详细的解释和丰富的实例&#xff0c;…