跟着GPT学设计模式之工厂模式

工厂模式(Factory Design Pattern)分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。在这三种细分的工厂模式中,简单工厂、工厂方法原理比较简单,在实际的项目中也比较常用。而抽象工厂的原理稍微复杂点,在实际的项目中相对也不常用。

工厂模式是一种常见的创建型设计模式,其主要目的是封装对象的创建过程,并隐藏具体实现细节。每种方式都有其独特的优点和缺点。

下面是工厂模式的一些优点:

  • 封装对象的创建:工厂模式将对象的创建过程封装在工厂类中,客户端只需要知道如何使用工厂类来获取所需对象,而无需关心对象创建的复杂逻辑。
  • 解耦合:工厂模式可以将具体产品类与客户端代码分离,客户端只与工厂接口进行交互,通过工厂接口获取具体产品,从而降低了客户端与具体产品之间的耦合度。
  • 可扩展性:当需要新增一种具体产品时,只需要添加相应的具体产品类和相应的工厂类,而不需要修改已经存在的代码,符合开闭原则。
  • 隐藏实现细节:工厂模式可以将具体产品类的实例化过程隐藏起来,对客户端来说,只需要了解工厂接口和产品接口的定义即可,无需了解具体产品的实现细节。

缺点:

  • 类的数量增加:引入工厂模式会增加代码中的类的数量,特别是在复杂系统中,可能会引入大量的工厂类,增加了系统的复杂度。
  • 不易理解:工厂模式的实现通常需要理解多个接口和类之间的关系,对于初学者或不熟悉该模式的开发人员来说,可能会增加理解难度。
  • 开发成本增加:引入工厂模式可以提高代码的灵活性和可扩展性,但同时也带来了一定的开发成本,需要额外编写工厂类和产品类。

选择是否使用工厂模式的标准:

  • 封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
  • 代码复用:创建代码抽离到独立的工厂类之后可以复用。
  • 隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。
  • 控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。

工厂模式的实现

简单工厂

说明

简单工厂模式(Simple Factory Pattern)通过一个工厂类来封装对象的创建过程,根据不同的参数返回对应的具体产品实例。

简单工厂模式包含以下角色:

  • 工厂(Factory):负责创建具体产品的工厂类,根据传入的参数来决定创建哪种具体产品。
  • 抽象产品(Product):定义了具体产品的公共接口,所有具体产品都必须实现该接口。
  • 具体产品(Concrete Product):实现抽象产品接口的具体产品类,由工厂类根据需要创建。

简单工厂模式的步骤如下:

  • 定义抽象产品接口(或抽象类),其中描述了产品的共同特征和行为。
  • 创建具体产品类,实现抽象产品接口。
  • 创建工厂类,提供一个静态方法或实例方法,根据传入的参数动态创建并返回具体产品实例。

优点:

  • 封装了对象的创建过程,客户端只需要知道工厂类和抽象产品类即可,无需关心具体产品的创建细节。
  • 解耦合,降低了客户端与具体产品类之间的依赖关系。
  • 可以集中管理对象的创建过程,有利于后续的扩展和维护。

缺点:

  • 当新增具体产品时,需要修改工厂类的代码,违反了开闭原则。
  • 工厂类的职责相对较重,包括对象的创建和判断逻辑,随着具体产品的增多,工厂类的代码会变得臃肿。

总的来说,简单工厂模式适用于创建的产品种类较少且不会经常变动的情况。如果产品种类较多或经常变动,建议使用工厂方法模式或者抽象工厂模式。

编程示例

有一个 Car 接口,以及实现类 Ford, Ferrari。

public interface Car {String getDescription();
}public class Ford implements Car {static final String DESCRIPTION = "This is Ford.";@Overridepublic String getDescription() {return DESCRIPTION;}
}public class Ferrari implements Car {static final String DESCRIPTION = "This is Ferrari.";@Overridepublic String getDescription() {return DESCRIPTION;}
}

以下的枚举用于表示支持的 Car 类型(Ford 和 Ferrari)

public enum CarType {FORD(Ford::new), FERRARI(Ferrari::new);private final Supplier<Car> constructor; CarType(Supplier<Car> constructor) {this.constructor = constructor;}public Supplier<Car> getConstructor() {return this.constructor;}
}

接着我们实现了一个静态方法 getCar 用于封装工厂类 CarsFactory 创建 Car 具体对象实例的细节。

public class CarsFactory {public static Car getCar(CarType type) {return type.getConstructor().get();}
}

现在我们可以在客户端代码中通过工厂类创建不同类型的 Car 对象实例。

var car1 = CarsFactory.getCar(CarType.FORD);
var car2 = CarsFactory.getCar(CarType.FERRARI);
LOGGER.info(car1.getDescription());
LOGGER.info(car2.getDescription());

程序输出:

This is Ford.
This is Ferrari.

工厂方法

说明

工厂方法模式(Factory Method Pattern)将对象的创建延迟到子类中进行。工厂方法模式通过定义一个创建对象的接口,但将具体的对象创建交给子类来实现。

工厂方法模式包含以下角色:

  • 抽象产品(Product):定义了具体产品的公共接口,所有具体产品都必须实现该接口。
  • 具体产品(Concrete Product):实现抽象产品接口的具体产品类。
  • 抽象工厂(Factory):定义了创建产品对象的接口,包含一个抽象的工厂方法,由子类来实现具体的产品创建。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,负责创建具体产品的实例。

工厂方法模式的步骤如下:

  • 定义抽象产品接口(或抽象类),其中描述了产品的共同特征和行为。
  • 创建具体产品类,实现抽象产品接口。
  • 定义抽象工厂接口,声明一个工厂方法用于创建产品对象。
  • 创建具体工厂类,实现抽象工厂接口,实现工厂方法,根据需要创建并返回具体产品实例。

优点:

  • 遵循开闭原则,新增具体产品时只需创建对应的具体工厂类,无须修改抽象工厂和其他已有类的代码。
  • 通过将对象创建的责任委托给子类,解耦了客户端与具体产品的依赖关系,客户端只需要依赖于抽象工厂和抽象产品。
  • 可以轻松扩展和增加新的产品族,每个产品族对应一个具体工厂类。

缺点:

  • 每新增一个具体产品类,就需要创建一个相应的具体工厂类,导致类的个数增多,增加了系统的复杂性。
  • 客户端在使用时需要了解和依赖具体工厂类,增加了客户端代码的复杂性。

工厂方法模式适用于需要创建多个具有共同接口或基类的产品对象的情况,且这些产品对象的创建逻辑相似但可能会有差异。它提供了一种灵活的扩展机制,能够方便地添加新的产品类型,而不影响已有的代码。

编程示例

例子: 铁匠生产武器。精灵需要精灵武器,而兽人需要兽人武器。根据客户来召唤正确类型的铁匠。

public interface Blacksmith {Weapon manufactureWeapon(WeaponType weaponType);
}public class ElfBlacksmith implements Blacksmith {public Weapon manufactureWeapon(WeaponType weaponType) {return ELFARSENAL.get(weaponType);}
}public class OrcBlacksmith implements Blacksmith {public Weapon manufactureWeapon(WeaponType weaponType) {return ORCARSENAL.get(weaponType);}
}

使用工厂方法:

/*** 抽象工厂 Blacksmith 具体工厂 OrcBlacksmith  ElfBlacksmith*/
Blacksmith blacksmith = new OrcBlacksmith();
Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
LOGGER.info("{} manufactured {}", blacksmith, weapon);
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
LOGGER.info("{} manufactured {}", blacksmith, weapon);blacksmith = new ElfBlacksmith();
weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
LOGGER.info("{} manufactured {}", blacksmith, weapon);
weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
LOGGER.info("{} manufactured {}", blacksmith, weapon);

程序输出:

The orc blacksmith manufactured an orcish spear
The orc blacksmith manufactured an orcish axe
The elf blacksmith manufactured an elven spear
The elf blacksmith manufactured an elven axe

抽象工厂(Abstract Factory)

通俗的讲就是工厂的工厂, 一个将单个但相关/从属的工厂分组在一起而没有指定其具体类别的工厂。

在抽象工厂模式中,有一个抽象工厂接口,定义了一系列用于创建产品对象的方法。每个具体的工厂类都实现了这个抽象工厂接口,并负责创建一组相关的产品。这些产品通常属于同一族或遵循某种主题。

关键要素:

  • 抽象工厂(Abstract Factory):定义了一组用于创建产品的方法。
  • 具体工厂(Concrete Factory):实现了抽象工厂的方法,负责创建一组相关的产品。
  • 抽象产品(Abstract Product):定义了产品的共同接口。
  • 具体产品(Concrete Product):实现了抽象产品的接口,由具体工厂创建。

优点:

  • 将产品的创建与使用相分离,客户端只需使用抽象工厂接口,无需关注具体的产品创建过程。
  • 更易于扩展和替换产品族,只需要添加新的具体工厂和具体产品即可。
编程示例

以下是抽象工厂模式的简单示例,其中AbstractFactory为抽象工厂:

// 抽象产品A
interface AbstractProductA {void operationA();
}// 具体产品A1
class ConcreteProductA1 implements AbstractProductA {public void operationA() {System.out.println("ConcreteProductA1 operationA");}
}// 具体产品A2
class ConcreteProductA2 implements AbstractProductA {public void operationA() {System.out.println("ConcreteProductA2 operationA");}
}// 抽象产品B
interface AbstractProductB {void operationB();
}// 具体产品B1
class ConcreteProductB1 implements AbstractProductB {public void operationB() {System.out.println("ConcreteProductB1 operationB");}
}// 具体产品B2
class ConcreteProductB2 implements AbstractProductB {public void operationB() {System.out.println("ConcreteProductB2 operationB");}
}// 抽象工厂
interface AbstractFactory {// 减少简单工厂的数量AbstractProductA createProductA();AbstractProductB createProductB();
}// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA1();}public AbstractProductB createProductB() {return new ConcreteProductB1();}
}// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {public AbstractProductA createProductA() {return new ConcreteProductA2();}public AbstractProductB createProductB() {return new ConcreteProductB2();}
}// 使用抽象工厂创建产品
public class Client {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();AbstractProductA productA1 = factory1.createProductA();AbstractProductB productB1 = factory1.createProductB();productA1.operationA();productB1.operationB();AbstractFactory factory2 = new ConcreteFactory2();AbstractProductA productA2 = factory2.createProductA();AbstractProductB productB2 = factory2.createProductB();productA2.operationA();productB2.operationB();}
}

输出

ConcreteProductA1 operationA
ConcreteProductB1 operationB
ConcreteProductA2 operationA
ConcreteProductB2 operationB

以上内容基于GPT创建和整理。

参考

  • 设计模式Java实现
  • 设计模式之美-王争

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

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

相关文章

【小收获】给定一个自定义的大小关系,然后给出其中两个元素,要求判断它们的大小关系

思路&#xff1a;由于该自定义的大小关系编译器并不知道&#xff0c;所以可以给它们都搞一个下标&#xff0c;从而根据下标的大小关系去判断各个元素之间的大小关系 例如&#xff1a;扑克牌中单张牌的大小关系为&#xff1a;3<4<5<6<7<8<9<X<J<Q<…

k8s篇之underlay网络和overlay区别

k8s中underlay网络和overlay区别 一、网络 1 Overlay网络&#xff1a; Overlay叫叠加网络也叫覆盖网络&#xff0c;指的是在物理网络的基础之上迭代实现新的虚拟网络&#xff0c;即可使网络中的容器可以互相通信。 优点是对物理网络的兼容性比较好&#xff0c;可以实现pod的…

TensorFlow2.0教程3-CNN

` 文章目录 基础CNN网络读取数据卷积层池化层全连接层模型配置模型训练CNN变体网络简单的深度网络添加了其它功能层的深度卷积NIN网络文本卷积基础CNN网络 读取数据 import numpy as np import tensorflow as tf import tensorflow.keras as keras import tensorflow.keras.la…

uniapp中在组件中使用被遮挡或层级显示问题

uniapp中在组件中使用或croll-view标签内使用uni-popup在真机环境下会被scroll-view兄弟元素遮挡&#xff0c;在开发环境下和安卓系统中可以正常显示&#xff0c;但在ios中出现了问题 看了许多文章都没有找到问题的原因&#xff0c;最后看到这一个文章http://t.csdnimg.cn/pvQ…

acwing算法基础之数据结构--STL简介

目录 1 基础知识2 模板3 使用示例3.1 vector3.2 pair3.3 string3.4 queue 1 基础知识 无。 2 模板 vector, 变长数组&#xff0c;倍增的思想size() 返回元素个数empty() 返回是否为空clear() 清空front()/back() 使用时&#xff0c;必须判断向量类容器非空push_back()/po…

C/S架构学习之基于UDP的本地通信(服务器)

基于UDP的本地通信&#xff08;服务器&#xff09;&#xff1a;创建流程&#xff1a;一、创建数据报式套接字&#xff08;socket函数&#xff09;&#xff1a; int sock_fd socket(AF_UNIX,SOCK_DGRAM,0);if(-1 sock_fd){perror("socket error");exit(-1);}二、创建…

138.随机链表的复制(LeetCode)

深拷贝&#xff0c;是指将该链表除了正常单链表的数值和next指针拷贝&#xff0c;再将random指针进行拷贝 想法一 先拷贝出一份链表&#xff0c;再对于每个节点的random指针&#xff0c;在原链表进行遍历&#xff0c;找到random指针的指向&#xff0c;最后完成拷贝链表random…

Docker 和 Kubernetes ,技术相同之处,和不同之处

目录 Docker 技术相同之处&#xff1a; 不同之处&#xff1a; Kubernetes 技术相同之处&#xff1a; 不同之处&#xff1a; Docker 技术相同之处&#xff1a; 容器化&#xff1a; Docker 和 Kubernetes 都是容器技术的代表。Docker 利用容器技术将应用程序及其所有依赖项…

CSS3 分页、框大小、弹性盒子

一、CSS3分页&#xff1a; 网站有很多个页面&#xff0c;需要使用分页来为每个页面做导航。示例&#xff1a; <style> ul.pagination { display: inline-block; padding: 0; margin: 0; } ul.pagination li {display: inline;} ul.pagination li a { color: black; f…

SW如何显示样条曲线的控标

刚刚学习隔壁老王的sw画图时&#xff0c;怎么点都点不出样条曲线的控标&#xff0c;于是果断查询了一下解决方法&#xff0c;其实很简单&#xff0c;只不过是培训机构故意不说&#xff0c;叫你还解决不了&#xff0c;难受了就会花钱买他们的课了。毕竟如果学会了怎么解决问题了…

数据结构之双向链表

目录 引言 链表的分类 双向链表的结构 双向链表的实现 定义 创建新节点 初始化 打印 尾插 头插 判断链表是否为空 尾删 头删 查找与修改 指定插入 指定删除 销毁 顺序表和双向链表的优缺点分析 源代码 dlist.h dlist.c test.c 引言 数据结构…

C语言算术运算符

常用算术运算符 正 - 负 加 - 减 * 乘 / 除 % 取余 --&#xff08;后面讲&#xff09; 运算符术语示例表示结果正号33-负号-3-3加10 515-减10 - 55*乘10 * 550/除10 / 52%取余&#xff08;取模&#xff09;10 % 31 算术运算符注意事项 注意事项1&#xff1a; 除法运算时&…

AUTOSAR汽车电子嵌入式编程精讲300篇-智能阀CAN总线延时边界确定(续)

目录 3.2 单路智能阀系统延时边界确定 3.3 单路智能阀系统CAN通信延时边界仿真分析

Qt TCP/IP网络通信

TCP服务器部分&#xff1a; 创建TCP服务器&#xff1a; #include <QTcpServer> QTcpServer *tcpServer; //TCP服务器 tcpServernew QTcpServer(this);TCP服务器来连接的信号与槽&#xff1a; connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()…

devops完整搭建教程(gitlab、jenkins、harbor、docker)

devops完整搭建教程&#xff08;gitlab、jenkins、harbor、docker&#xff09; 文章目录 devops完整搭建教程&#xff08;gitlab、jenkins、harbor、docker&#xff09;1.简介&#xff1a;2.工作流程&#xff1a;3.优缺点4.环境说明5.部署前准备工作5.1.所有主机永久关闭防火墙…

360导航恶意修改浏览器启动页!我的chrome和IE均中招,如何解决?

0&#xff0c;关闭360等“安全”软件 1&#xff0c;按下组合键winR 2&#xff0c;输入regedit&#xff0c;回车 3&#xff0c;按下组合键ctrlF 4&#xff0c;输入http://hao.360.cn&#xff0c;查找下一个 5&#xff0c;查到一个注册表键值就删一个&#xff0c;一个不放过…

学习c#的第五天

目录 C# 运算符 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 C# 中的运算符优先级 C# 运算符 算术运算符 下表显示了 C# 支持的所有算术运算符。假设变量 A 的值为 10&#xff0c;变量 B 的值为 20&#xff0c;则&#xff1a; 运算符描述实例…

CentOs7 NAT模式连接网络

1.配置动态网络 1.1 检查主机网卡配置 检查主机的网络设置 进入控制面板&#xff0c;找到网络共享中心 查看适配器是否都已经开启 1.2 设置虚拟机的网络配置 打开虚拟机网络配置设置&#xff0c;对网卡VMnet8 进行设置 记住网关 全部选择应用&#xff0c;确定 1.3 设置…

C# List<T>.IndexOf()方法的使用

C#中的List<T>.IndexOf()方法用于查找指定元素在列表中的索引位置。它返回第一个匹配项的索引&#xff0c;如果未找到匹配项&#xff0c;则返回-1。 语法&#xff1a;有三种参数可选 int List<T>.IndexOf(T item); int List<T>.IndexOf(T item, int star…