【设计模式】-工厂模式

news2024/11/16 20:44:33

工厂模式是一种创建型设计模式,它提供了一种在不指定具体类的情况下创建对象的方法。工厂模式的核心思想是将对象的创建与使用分离,降低系统的耦合度,使系统更加灵活、可扩展。

工厂模式主要分为三种类型:简单工厂模式、工厂方法模式和抽象工厂模式。下面我将分别介绍这三种工厂模式,并给出相应的Java实例代码。

三种模式介绍

1. 简单工厂模式

简单工厂模式又称为静态工厂方法模式,它由一个工厂类根据传入的参数决定创建哪一种产品类的实例。
在这里插入图片描述

Java实例代码:

// 产品接口
public interface Car {
    void drive();
}

// 具体产品类1
public class BMW implements Car {
    @Override
    public void drive() {
        System.out.println("Driving BMW");
    }
}

// 具体产品类2
public class Benz implements Car {
    @Override
    public void drive() {
        System.out.println("Driving Benz");
    }
}

// 工厂类
public class CarFactory {
    public static Car createCar(String type) {
        if ("BMW".equalsIgnoreCase(type)) {
            return new BMW();
        } else if ("Benz".equalsIgnoreCase(type)) {
            return new Benz();
        } else {
            throw new IllegalArgumentException("Invalid car type: " + type);
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Car bmw = CarFactory.createCar("BMW");
        bmw.drive();
        
        Car benz = CarFactory.createCar("Benz");
        benz.drive();
    }
}

2. 工厂方法模式

工厂方法模式将对象的创建延迟到子类中进行,工厂类不再负责具体产品的创建,而是提供一个创建产品的抽象方法,由子类实现具体的创建逻辑。
在这里插入图片描述

Java实例代码:

// 产品接口
public interface Car {
    void drive();
}

// 具体产品类1
public class BMW implements Car {
    @Override
    public void drive() {
        System.out.println("Driving BMW");
    }
}

// 具体产品类2
public class Benz implements Car {
    @Override
    public void drive() {
        System.out.println("Driving Benz");
    }
}

// 工厂接口
public interface CarFactory {
    Car createCar();
}

// 具体工厂类1
public class BMWFactory implements CarFactory {
    @Override
    public Car createCar() {
        return new BMW();
    }
}

// 具体工厂类2
public class BenzFactory implements CarFactory {
    @Override
    public Car createCar() {
        return new Benz();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        CarFactory bmwFactory = new BMWFactory();
        Car bmw = bmwFactory.createCar();
        bmw.drive();
        
        CarFactory benzFactory = new BenzFactory();
        Car benz = benzFactory.createCar();
        benz.drive();
    }
}

3. 抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)提供了一种方式来封装一组具有共同主题的单个工厂,而不需要指定它们的具体类。客户端使用抽象工厂来创建一系列的相关或相互依赖的对象,而不需要指定它们具体的类。这样可以将客户端与具体产品的创建分离,使得系统更易于扩展和维护。
在这里插入图片描述

下面是一个简单的Java代码实例,展示了抽象工厂模式的应用:

// 抽象产品A
public interface Gui {
    void draw();
}

// 具体产品A1
public class WinGui implements Gui {
    @Override
    public void draw() {
        System.out.println("Drawing Windows GUI");
    }
}

// 具体产品A2
public class MacGui implements Gui {
    @Override
    public void draw() {
        System.out.println("Drawing MacOS GUI");
    }
}

// 抽象产品B
public interface Button {
    void click();
}

// 具体产品B1
public class WinButton implements Button {
    @Override
    public void click() {
        System.out.println("Clicking Windows Button");
    }
}

// 具体产品B2
public class MacButton implements Button {
    @Override
    public void click() {
        System.out.println("Clicking MacOS Button");
    }
}

// 抽象工厂
public interface UiFactory {
    Gui createGui();
    Button createButton();
}

// 具体工厂1
public class WinUiFactory implements UiFactory {
    @Override
    public Gui createGui() {
        return new WinGui();
    }

    @Override
    public Button createButton() {
        return new WinButton();
    }
}

// 具体工厂2
public class MacUiFactory implements UiFactory {
    @Override
    public Gui createGui() {
        return new MacGui();
    }

    @Override
    public Button createButton() {
        return new MacButton();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 使用Windows风格的UI组件
        UiFactory winFactory = new WinUiFactory();
        Gui winGui = winFactory.createGui();
        Button winButton = winFactory.createButton();
        winGui.draw();
        winButton.click();
        
        // 使用MacOS风格的UI组件
        UiFactory macFactory = new MacUiFactory();
        Gui macGui = macFactory.createGui();
        Button macButton = macFactory.createButton();
        macGui.draw();
        macButton.click();
    }
}

在这个例子中,我们定义了两个抽象产品:GuiButton,分别代表图形用户界面和按钮。然后,我们为每种操作系统(Windows和MacOS)创建了具体的产品实现。WinGuiMacGuiGui 的具体实现,而 WinButtonMacButtonButton 的具体实现。

我们定义了一个抽象工厂接口 UiFactory,它包含了创建 GuiButton 的方法。然后,我们为每种操作系统创建了一个具体的工厂实现:WinUiFactoryMacUiFactory。这些工厂负责创建对应操作系统的具体产品实例。

在客户端代码中,我们可以根据需要选择使用哪种风格的UI组件。通过创建不同风格的工厂实例,并调用其创建方法,我们可以得到对应风格的 GuiButton 对象,并调用它们的方法。这样,客户端代码与具体产品的创建逻辑被完全分离,提高了系统的灵活性和可维护性。

对比

是不是还有点晕,好像“工厂方法模式”和“抽象工厂模式”傻傻分不清楚啊。那我们来张表对比一下,就清晰了:

特性/模式简单工厂模式工厂方法模式抽象工厂模式
结构一个工厂类负责创建所有产品抽象工厂类定义接口,具体工厂类负责创建对应产品抽象工厂类定义创建产品族的接口,具体工厂类负责创建多个具体产品
扩展性不符合“开闭原则”,新增产品需修改工厂类符合“开闭原则”,新增产品只需添加新类和工厂子类新增产品族符合“开闭原则”,单独新增产品不符合
使用场景产品种类少且不常变动产品种类多且经常变动需要创建一系列相互关联或依赖的产品
责任划分工厂类负责创建所有产品实例具体工厂子类负责创建对应产品实例具体工厂子类负责创建多个相互关联的产品实例
客户端与产品创建客户端直接调用工厂类创建产品客户端通过工厂子类接口创建产品客户端通过工厂子类接口创建多个相关产品
灵活性较低,工厂类集中了所有产品创建逻辑较高,产品创建逻辑分散在工厂子类中较高,可以灵活创建多个相关产品
代码复杂性较低,结构简单中等,需要定义抽象工厂和具体工厂类较高,涉及多个抽象产品类和具体产品类

了解下“产品族”是个啥:
在这里插入图片描述
在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。这些产品虽然在类型上有所差异,但它们在功能上是相互关联或依赖的。

为了更好地理解这个概念,我们可以以一个实际的例子来说明。假设有一个电器制造工厂,它生产了电视机和电冰箱两种产品。这两种产品分别属于不同的产品等级结构:电视机有其自己的产品等级结构,包括不同品牌、型号的电视机;电冰箱也有其独立的产品等级结构,涵盖了各种类型、规格的电冰箱。然而,在这个例子中,由于它们都是由同一个电器制造工厂生产的,因此电视机和电冰箱构成了一个产品族。

这个产品族中的每个成员(即电视机和电冰箱)都有其特定的功能和用途,但它们都是电器制造工厂的产品,共享了相同的生产标准和质量控制体系。因此,它们在功能上是相互关联或依赖的,构成了一个有机的整体。

抽象工厂模式通过提供一个接口,使得客户端可以创建一系列相关或相互依赖的对象,而无需指定它们具体的类。在上面的例子中,客户端可以通过调用电器制造工厂的接口,一次性地获取到电视机和电冰箱这两种产品,而无需关心它们具体的实现细节。

这下是不是就清晰了。OVER。

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

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

相关文章

苍穹外卖-day06:HttpClient、微信小程序开发、微信登录(业务流程)、导入商品浏览功能代码(业务逻辑)

苍穹外卖-day06 课程内容 HttpClient微信小程序开发微信登录导入商品浏览功能代码 功能实现:微信登录、商品浏览 微信登录效果图: 商品浏览效果图: 1. HttpClient 1.1 介绍 HttpClient 是Apache Jakarta Common 下的子项目,…

苍穹外卖-day04:项目实战-套餐管理(新增套餐,分页查询套餐,删除套餐,修改套餐,起售停售套餐)业务类似于菜品模块

苍穹外卖-day04 课程内容 新增套餐套餐分页查询删除套餐修改套餐起售停售套餐 要求: 根据产品原型进行需求分析,分析出业务规则设计接口梳理表之间的关系(分类表、菜品表、套餐表、口味表、套餐菜品关系表)根据接口设计进行代…

C#重新认识笔记_ 点乘,叉乘

C#重新认识笔记_ 点积,叉乘 一、Dot Product 点乘: (Ax*Bx)(Ay*By)(Az*Bz)Dot Product 点积 利用点积,可以了解,两个向量(vector)的相关信息, …

el-form 的表单校验,如何验证某一项或者多项;validateField 的使用

通常对form表单的校验都是整体校验: this.$refs.form.validate( valid > {if (valid) {// 校验通过,业务逻辑代码...} }); 如果需要对表单里的特定一项或几项进行校验,应该如何实现? 业务场景:下图点探测按钮时…

CSS 零基础入门教程

目录 1. div 和 span2. 什么是CSS?3. CSS 引入方式3.1 内部样式表3.2 外部样式表3.3 行内样式 4. 选择器4.1 标签选择器4.2 类选择器4.3 id 选择器4.4 通配符选择器 5. CSS 基础属性6. 谷歌浏览器调试工具 正文开始。 1. div 和 span 在学习 CSS 之前,…

Redis 八种常用数据类型详解

夯实基础,这篇文章带着大家回顾一下 Redis 中的 8 种常用数据类型: 5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zse…

redis学习-List类型相关命令以及特殊情况分析

目录 1. lpush key value1 value2 ... 2. lrange key start end 3. lpop key num 4. rpush key value1 value2 ... 5. rpop key num 6. lindex key index 7. llen key 8. lrem key num value 9. rpoplpush key1 key2 10. lset key index value 11. linsert key before/after…

算法---二分查找练习-1(在排序数组中查找元素的第一个和最后一个位置)

在排序数组中查找元素的第一个和最后一个位置 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址:点这里 2. 讲解算法原理 算法原理如下: 首先,判断数组是否为空,如果为空,则直接返回{-1, -1}表示没有找到目…

深入解析JVM加载机制

一、背景 Java代码被编译器变成生成Class字节码,但字节码仅是一个特殊的二进制文件,无法直接使用。因此,都需要放到JVM系统中执行,将Class字节码文件放入到JVM的过程,简称类加载。 二、整体流程 三、阶段逻辑分析 3…

PostgreSQL中vacuum 物理文件truncate发生的条件

与我联系: 微信公众号:数据库杂记 个人微信: iiihero 我是iihero. 也可以叫我Sean. iiheroCSDN(https://blog.csdn.net/iihero) Sean墨天轮 (https://www.modb.pro/u/16258) 数据库领域的资深爱好者一枚。 水木早期数据库论坛发起人 db2smth就是俺&am…

世界第一个AI软件工程师问世!

2024年3月13日,科技公司Cognition推出了世界上第一位人工智能软件工程师Devin AI。这项创新有望利用人工智能编码和机器学习的力量加快发展。Devin AI不仅仅是帮助;它是一个成熟的队友,发挥智能编码自动化和自主人工智能编码的魔力&#xff0…

Spring Bean的生命周期流程

前言 Java 中的公共类称之为Java Bean,而 Spring 中的 Bean 指的是将对象的生命周期,交给Spring IoC 容器来管理的对象。所以 Spring 中的 Bean 对象在使用时,无需通过 new 来创建对象,只需要通过 DI(依赖注入&#x…

数字化转型导师坚鹏:人工智能在金融机构数字化转型中的应用

人工智能在金融机构数字化转型中的应用 课程背景: 金融机构数字化转型离不开人工智能,在金融机构数字化转型中,人工智能起到至关重要的作用,很多机构存在以下问题: 不清楚人工智能产业对我们有什么影响?…

【数据可信流通,从运维信任到技术信任】

1. 数据可信流通体系 信任的基石: 身份的可确认利益可依赖能力有预期行为有后果 2.内循环——>外循环 内循环:数据持有方在自己的运维安全域内队自己的数据使用和安全拥有全责。 外循环:数据要素在离开持有方安全域后,持有方…

函数-Python

师从黑马程序员 函数初体验 str1"asdf" str2"qewrew" str3"rtyuio" def my_len(data):count0for i in data:count1print(f"字符串{data}的长度是{count}")my_len(str1) my_len(str2) my_len(str3) 函数的定义 函数的调用 函数名&a…

12_Linux内核结构

Linux内核结构 1.内核的主要组成部分 Linux 内核主要的 5 个部分:进程调度、内存管理、虚拟文件系统、网络接口、进程通信。在系统移植的时候,它们是内核的基本元素,这 5 个部分之间的关系,如图所示: 进程调度&#…

检查约束

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 检查约束 检查约束指的是在数据列上设置一些过滤条件,当过滤条件满足的时候才可以进行保存,如果不满足则出现错误。例如,设置年龄的信息…

微服务:高并发带来的问题的容错方案

1.相关脚本(陈天狼) 启动nacos客户端: startup.cmd -m standalone 启动sentinel控制台: # 直接使⽤jar命令启动项⽬(控制台本身是⼀个SpringBoot项⽬) java -Dserver.port8080 -Dcsp.sentinel.dashboard.serverlocalhost:808…

蓝桥杯冲刺_二分(正在补题)

二分一定要是单调队列&#xff0c;单调才具有二段性 特征 最小值最大化 最大值最小化 15 届蓝桥杯 14 天省赛冲刺营 1 期 - M次方根 - 蓝桥云课 (lanqiao.cn) #include <bits/stdc.h> using namespace std;double n,l,r,mid; double eps1e-8;bool check(double mid,i…

JavaSE综合练习-图书系统1.0

Main import book.BookList; import user.AdminUser; import user.NormalUser; import user.User; import java.util.Scanner;//程序入口函数 public class Main {public static User login(){Scanner scannernew Scanner(System.in);System.out.println("请输入你的姓名…