设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)

news2024/12/28 20:21:57

文章目录

  • 1、工厂模式概述
    • 1)特点:
    • 2)主要角色:
    • 3)工作流程:
    • 4)优点
    • 5)缺点
    • 6)适用场景
  • 2、简单工厂模式(静态工厂模式)
    • 1) 在简单工厂模式中,有三个主要角色:
    • 2) 简单工厂模式的优点包括:
    • 3) 简单工厂模式也有一些限制和考虑因素:
    • 4) 简单工厂模式适用场景:
    • 5) 简单工厂UML类图:
    • 6) 代码示例:
  • 3、工厂方法模式
    • 1) 在工厂方法模式中,有4个主要角色:
    • 2) 工厂方法模式的工作流程:
    • 3) 工厂方法模式适用场景:
    • 4) 工厂方法模式UML类图:
    • 5) 代码示例:
  • 4、抽象工厂模式
    • 1) 在抽象工厂模式中,有4个主要角色:
    • 2) 抽象工厂模式的工作流程:
    • 3) 抽象工厂模式的优点:
    • 4) 抽象工厂模式的缺点:
    • 5) 抽象工厂模式适用场景:
    • 6) 抽象工厂模式UML类图:
    • 7) 代码示例:

1、工厂模式概述

1)特点:

工厂模式(Factory Pattern)是一种创建型设计模式,旨在提供一种统一的方式来创建对象,将对象的实例化过程封装在一个单独的类中。工厂模式通过定义一个公共的接口来创建对象,但允许子类决定实例化哪个类。这样可以将对象的实例化与客户端代码的耦合度降到最低,同时也提供了一种可扩展的方式来创建对象。

2)主要角色:

  • 抽象产品:定义产品的通用接口,具体产品类需要实现该接口。
  • 具体产品:实现抽象产品接口的类,代表实际的产品。
  • 抽象工厂:定义创建产品的接口,可以是抽象类或接口,声明工厂方法。
  • 具体工厂:实现抽象工厂的接口,负责创建具体产品对象。

3)工作流程:

  • 客户端通过抽象工厂请求产品实例。
  • 具体工厂类根据请求创建并返回对应的具体产品。
  • 客户端使用产品实例,而不直接依赖具体产品类。

4)优点

  • 解耦:将对象的创建与使用分离,降低了客户端与具体产品的耦合度。
  • 易扩展:可以通过新增具体产品和工厂,轻松扩展系统而无需修改现有代码。
  • 灵活性:可以动态替换产品实例,提供灵活的对象创建方式。

5)缺点

  • 系统复杂性增加:引入了多个类和接口,增加了系统的复杂度。
  • 代码量增加:添加新产品时,需要创建新的具体产品类和对应的具体工厂类。
  • 类的爆炸性增长:随着产品族增加,具体工厂类的数量可能大幅增长。

6)适用场景

  • 需要统一管理对象创建过程的场景。
  • 系统需要频繁扩展和替换产品类的场景。

2、简单工厂模式(静态工厂模式)

简单工厂模式(Simple Factory Pattern) 是工厂模式的一种简化形式,也被称为静态工厂模式。它通过一个专门的工厂类来创建对象,而无需将对象的实例化过程放在客户端代码中。

1) 在简单工厂模式中,有三个主要角色:

  • 抽象产品(Abstract Product):定义产品的通用接口,所有具体产品类都应该实现这个接口。
  • 具体产品(Concrete Product):实现抽象产品接口的具体类。
  • 简单工厂(Simple Factory):负责创建具体产品的工厂类。它通常包含一个静态方法,根据客户端的请求来创建并返回具体产品的实例

2) 简单工厂模式的优点包括:

  • 将对象的创建过程集中在一个工厂类中,减少了客户端代码与具体产品的直接耦合
  • 可以通过简单工厂类的静态方法来创建产品,简化了客户端的调用代码
  • 可以轻松添加新的产品,只需修改简单工厂类的创建方法,而无需修改客户端代码。

3) 简单工厂模式也有一些限制和考虑因素:

  • 工厂类负责创建所有产品,当产品种类较多时,工厂类的代码可能会变得复杂
  • 添加新产品时,需要修改工厂类的代码,违反了开闭原则

4) 简单工厂模式适用场景:

  • 简单工厂模式适用于需要根据客户端请求来创建不同类型对象的场景,但产品种类较少且不经常变化的情况。它提供了一种简单的方式来封装对象的创建过程,降低了客户端代码与具体产品的耦合度。

5) 简单工厂UML类图:

在这里插入图片描述

6) 代码示例:

// 抽象产品类
abstract class Product {
    public abstract void use();
}

// 具体产品类A
class ConcreteProductA extends Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}

// 具体产品类B
class ConcreteProductB extends Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}

// 简单工厂类
class SimpleFactory {
    public Product createProduct(String type) {
        if (type.equals("A")) {
            return new ConcreteProductA();
        } else if (type.equals("B")) {
            return new ConcreteProductB();
        } else {
            // 处理未知产品类型的情况
            return null;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        // 使用简单工厂创建产品
        SimpleFactory factory = new SimpleFactory();

        Product productA = factory.createProduct("A");
        if (productA != null) {
            productA.use();
        }

        Product productB = factory.createProduct("B");
        if (productB != null) {
            productB.use();
        }

        Product unknownProduct = factory.createProduct("C");
        if (unknownProduct == null) {
            System.out.println("Unknown product type.");
        }
    }
}

3、工厂方法模式

工厂方法模式(Factory Method Pattern) 是一种创建型设计模式,它提供了一种将对象的创建委托给子类的方式。在工厂方法模式中,定义一个用于创建对象的接口,但让子类决定实例化哪个类。这样可以将对象的创建与使用解耦,使得系统在不修改具体产品类的情况下可以引入新的产品。

1) 在工厂方法模式中,有4个主要角色:

  • 抽象产品(Abstract Product):定义产品的通用接口,所有具体产品类都应该实现这个接口。
  • 具体产品(Concrete Product):实现抽象产品接口的具体类,是工厂方法模式所创建的对象。
  • 抽象工厂(Factory):定义了工厂方法的接口,负责创建抽象产品的对象。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,具体工厂类根据具体业务逻辑,创建具体产品的对象。

2) 工厂方法模式的工作流程:

  • 客户端通过调用具体工厂类的工厂方法来创建产品对象。
  • 具体工厂类根据客户端的请求,调用具体产品类的构造方法创建具体产品对象。
  • 具体工厂类将创建的具体产品对象返回给客户端。

通过工厂方法模式,客户端与具体产品类解耦,客户端只需关心抽象产品和抽象工厂,具体产品的创建由具体工厂类来完成。这样,当需要引入新的产品时,只需创建一个新的具体产品类和对应的具体工厂类,而不需要修改客户端代码。

3) 工厂方法模式适用场景:

  • 当一个类无法预知它需要创建的对象的具体类时,可以使用工厂方法模式。
  • 当一个类希望将对象的创建责任委托给多个子类中的某一个时,可以使用工厂方法模式。
  • 当一个类需要通过其子类来指定创建对象时,可以使用工厂方法模式。

总结来说,工厂方法模式通过定义一个创建对象的接口,将对象的实例化延迟到子类中去完成,实现了对象的创建与使用的解耦,提高了系统的可扩展性和灵活性。

4) 工厂方法模式UML类图:

在这里插入图片描述

5) 代码示例:

// 抽象产品类
abstract class Product {
    // 抽象方法
    public abstract void use();
}

// 具体产品类A
class ConcreteProductA extends Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA");
    }
}

// 具体产品类B
class ConcreteProductB extends Product {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductB");
    }
}

// 抽象工厂类
abstract class Factory {
    // 抽象工厂方法
    public abstract Product createProduct();

    // 打印产品使用信息
    public void print() {
        Product product = createProduct();
        product.use();
    }
}

// 具体工厂类A
class ConcreteFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂类B
class ConcreteFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

public class Main {
    public static void main(String[] args) {
        // 使用工厂类创建产品
        Factory factoryA = new ConcreteFactoryA();
        factoryA.print();

        Factory factoryB = new ConcreteFactoryB();
        factoryB.print();
    }
}


运行结果
Using ConcreteProductA
Using ConcreteProductB

4、抽象工厂模式

抽象工厂模式(Abstract Factory Pattern) 是一种创建型设计模式,旨在提供一种统一的方式来创建一系列相关或相互依赖的对象,而无需指定具体的类。它通过定义一个抽象工厂接口和一组具体工厂类,来创建一族产品对象。

1) 在抽象工厂模式中,有4个主要角色:

  • 抽象工厂(Abstract Product):定义了创建一族产品对象的接口。它通常包含一组用于创建不同产品的工厂方法。
  • 具体工厂(Concrete Product):实现了抽象工厂接口,负责创建具体的产品对象。
  • 抽象产品(Factory):定义了一族产品对象的通用接口。具体产品类应实现这个接口。
  • 具体产品(Concrete Factory):实现了抽象产品接口,是由具体工厂创建的对象。

2) 抽象工厂模式的工作流程:

  • 客户端通过抽象工厂接口来创建一族相关的产品对象。
  • 具体工厂类实现了抽象工厂接口,负责创建具体的产品对象。
  • 抽象工厂的工厂方法根据具体工厂的实现,创建并返回具体产品的实例。
  • 客户端使用返回的产品实例进行操作,而无需关心具体产品的实现细节。

3) 抽象工厂模式的优点:

  • 将对象的创建和使用分离,降低了客户端代码与具体产品的耦合度。
  • 提供了一种可替换的方式来创建一族相关产品,使得系统更加灵活和可维护。
  • 符合开闭原则,可以轻松添加新的具体工厂和产品类,扩展系统功能。

4) 抽象工厂模式的缺点:

  • 当产品族的数量增加时,抽象工厂和具体工厂的接口可能变得复杂,需要谨慎设计和管理。
  • 添加新的产品族可能需要修改抽象工厂和所有具体工厂的代码,违反了开闭原则。

5) 抽象工厂模式适用场景:

抽象工厂模式适用于需要创建一族相关产品对象的场景,其中产品之间存在一定的关联或依赖关系。它提供了一种统一的方式来管理产品的创建过程,将对象的创建与客户端代码解耦,同时也支持动态替换和扩展对象的创建。

6) 抽象工厂模式UML类图:

在这里插入图片描述

7) 代码示例:

// 抽象产品A
interface AbstractProductA {
    void use();
}

// 具体产品A1
class ConcreteProductA1 implements AbstractProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA1");
    }
}

// 具体产品A2
class ConcreteProductA2 implements AbstractProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA2");
    }
}

// 抽象产品B
interface AbstractProductB {
    void eat();
}

// 具体产品B1
class ConcreteProductB1 implements AbstractProductB {
    @Override
    public void eat() {
        System.out.println("Eating ConcreteProductB1");
    }
}

// 具体产品B2
class ConcreteProductB2 implements AbstractProductB {
    @Override
    public void eat() {
        System.out.println("Eating ConcreteProductB2");
    }
}

// 抽象工厂
interface AbstractFactory {
    AbstractProductA createProductA();
    AbstractProductB createProductB();
}

// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB2();
    }
}

// 主程序
public class Main {
    public static void main(String[] args) {
        // 使用具体工厂1创建产品族1
        AbstractFactory factory1 = new ConcreteFactory1();
        AbstractProductA productA1 = factory1.createProductA();
        AbstractProductB productB1 = factory1.createProductB();

        productA1.use();
        productB1.eat();

        // 使用具体工厂2创建产品族2
        AbstractFactory factory2 = new ConcreteFactory2();
        AbstractProductA productA2 = factory2.createProductA();
        AbstractProductB productB2 = factory2.createProductB();

        productA2.use();
        productB2.eat();
    }
}



运行结果
Using ConcreteProductA1
Eating ConcreteProductB1
Using ConcreteProductA2
Eating ConcreteProductB2

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

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

相关文章

基于SpringBoot的宠物服务系统+uniapp小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

浏览器插件利器--allWebPluginV2.0.0.20-alpha版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品,致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器,实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

小琳AI课堂:深入学习BERT

大家好,这里是小琳AI课堂。今天我们来聊聊BERT,这个在自然语言处理(NLP)领域掀起革命风潮的模型。 出现背景 在BERT之前,NLP领域主要依赖RNN或CNN模型,这些模型大多只能单向处理文本,从左到右…

【全网首创】大模型LLM-RAG知识库问答项目实战课

在大数据和人工智能迅猛发展的今天,大模型和知识库的结合成为了理论探索和实际应用的重要方向。LLM-RAG项目课程正是围绕这一热点展开,旨在通过系统性的教学,帮助学员掌握从项目部署、模块开发到实际应用的完整流程。课程共有43课时&#xff…

SprinBoot+Vue公交智能化系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质…

高可用架构模式

架构里比较重要的是高性能、高可用、高扩展性。上次是高性能,这次是高可用。 对一般的项目而言,高可用主要用公司提供的基建,如多机房部署、主从等。但有些项目确实需要思考更多高可用的事项,如资源不足的情况下要做好限流或者降…

gdb中使用python脚本

1、入门案例 首先有1个a.cpp&#xff0c;代码如下&#xff1a; #include <map> #include <set> #include <iostream> #include <string>using namespace std;struct MyStruct {std::string mName;std::map<int, std::string> mField1;std::set…

SpringBoot3 简单集成 Mybatis plus

SpringBoot3 集成 Mybatis plus 1、引入Mybatisplus的starter <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency>2、引入数据…

JVM3-双亲委派机制

目录 概述 作用 如何指定加载类的类加载器&#xff1f; 面试题 打破双亲委派机制 自定义类加载器 线程上下文类加载器 Osgi框架的类加载器 概述 由于Java虚拟机中有多个类加载器&#xff0c;双亲委派机制的核心是解决一个类到底由谁加载的问题 双亲委派机制&#xff…

Qt中window frame的影响

window frame 在创建图形化界面的时候&#xff0c;会创建窗口主体&#xff0c;上面会多出一条&#xff0c;周围多次一圈细边&#xff0c;这就叫window frame窗口框架&#xff0c;这是操作系统自带的。 这个对geometry的一些属性有一定影响&#xff0c;主要体现在Qt坐标系体系…

安装Seata-Service,Seata服务中心安装,并完成Nacos注册

一、下载服务器软件包 从 Releases apache/incubator-seata GitHub ,下载服务器软件包&#xff0c;将其解压缩。 版本选择&#xff1a; 1可以从官网查询版本对照。 2.可以在项目中&#xff0c;倒入seata版依赖 <!-- seata--><dependency><groupId&…

嘉立创中秋福利来啦!

单笔订单商品实付慢2万送良品铺子月饼 多品牌折扣 快来立创商城一探究竟吧~ 立创商城_一站式电子元器件采购自营商城_嘉立创电子商城 (szlcsc.com)

深度学习中常见的权重参数初始化方法

在深度学习中&#xff0c;权重参数的初始化对模型的训练过程和性能有着非常重要的影响。一个好的权重初始化方法能够帮助模型更快收敛、避免梯度爆炸或梯度消失等问题。以下是几种常见的权重初始化方法及其背后的原理。 1. 零初始化&#xff08;Zero Initialization&#xff0…

每天学习一个字符串类函数之memmove函数

目录 前言&#xff1a; 一、头文件 二、memmove函数的作用 三、理解memmove函数的定义 1、返回类型 2、参数 四、使用memmove函数 案例1&#xff1a; 案例2&#xff1a; 五、解决数据拷贝之前被覆盖的方法 六、模拟实现memmove函数 前言&#xff1a; 上一篇博客&#xff0c;我…

【C++】STL容器详解【上】

目录 一、STL基本概念 二、STL的六大组件 三、string容器常用操作 3.1 string 容器的基本概念 3.2 string 容器常用操作 3.2.1 string 构造函数 3.2.2 string基本赋值操作 3.2.3 string存取字符操作 3.2.4 string拼接字符操作 3.2.5 string查找和替换 3.2.6 string比…

Unity Shader实现简单的各向异性渲染(采用各向异性形式的GGX分布)

目录 准备工作 BRDF部分 Unity部分 代码 实现的效果 参考 最近刚结束GAMES202的学习&#xff0c;准备慢慢过渡到GAMES103。GAMES103的作业框架为Unity&#xff0c;并没有接触过&#xff0c;因此准备先学一点Unity的使用。刚好101和202都是渲染相关的&#xff0c;因此先学习…

如何查看Mac的处理器架构‌‌是ARM还是x86

‌通过命令行查看Mac的处理器架构‌‌ 打开终端&#xff08;Terminal&#xff09;。输入命令 uname -m 并回车。如果输出结果是 arm64&#xff0c;则表示你的Mac使用的是ARM架构&#xff1b;如果输出结果是 x86_64&#xff0c;则表示你的Mac使用的是x86架构。 如图&#xff1…

牛客JZ36 二叉搜索树与双向链表 C++

牛客JZ36 二叉搜索树与双向链表 C 思路&#x1f9d0;&#xff1a; 由图所示&#xff0c;我们看出该链表走的是中序&#xff0c;所以我们可以使用中序遍历的方式来解决这个问题&#xff0c;在遍历过程中&#xff0c;我们创建一个前驱和一个后继结点&#xff0c;来进行链接。 并且…

基于stm32f407的跟随行驶系统项目报告(利用openmv+超声波模块)

2023年全国大学生电子设计竞赛&#xff08;TI杯&#xff09; 2024年05月29日 摘要 本项目的硬件结构&#xff1a;基于STM32F407芯片为主控芯片&#xff0c;由TB6612电机驱动&#xff0c;控制左右轮电机的转动控制小车提供前进前进的速度&#xff0c;通过控制两轮的差数达到稳定…

Hive中的分区表与分桶表详解

目录 分区表和分桶表 分区表 分区表基本语法 1. 创建分区表 2. 分区表读写数据 1&#xff09;写数据 &#xff08;1&#xff09;LOAD &#xff08;2&#xff09;INSERT 2&#xff09;读数据 3. 分区表基本操作 1&#xff09;查看所有分区信息 2&#xff09;增加分区 …