设计模式5——抽象工厂模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。

抽象工厂模式(Abstract Factory)

是一种创建型模式。

目录

一、概述

二、优点

三、举例


一、概述

1、提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
2、和工厂方法模式不同的是,有多种类型的对象(产品)需要被实例化,同时工厂也被定义了多个不同产品创建的接口。

1.1、主要的角色分两种,但从代码(或技术)实现的角度看(为了充分使用面向对象语言的3大特性封装、继承、多态,还另外需要抽象类或接口)可能有4个:

  1. 工厂的抽象类或接口(单个) + 工厂的实现类(多个):控制创建哪些产品以及如何创建产品的类
  2. 产品的抽象类或接口(多个) + 产品实现类(多个):那些需要被创建(实例化)的类 

1.2、直观的理解上这些角色之间的关系如下:

1.3、通过技术实现的角度看,对象之间关系的UML图如下:

 

二、优点

  • 使得发起请求的对象和具体创建实例的过程分离

三、举例

 假设一个部门系统升级,涉及到两个表:部门表和用户表。原先这两表在数据库A里,升级后新加了个数据库B,也有部门表和用户表。现在为了兼容性,A和B两个库,和库里的两个表(部门表和用户表)都需要使用。数据库如下:

3.1、为了实现对不同数据库的不同表的访问和连接,分析步骤:

1、分析上述问题:

  • 抓住上面关键:有两个数据库,每个数据库又有两个表;
  • 两个数据库是不同的,但库里的两个表是相同的,都是一个用户表一个部门表;
  • 如果把两个库同名的表看成一样,那么逻辑上访问的就只有两个表,所以为了实现访问2个不同表,我们需要定义2个不同的接口,然后针对不同的数据库,我们还又需要设计不同实现类;
  • 我们发现这样下来会设计很多类,那么在真正使用时需要创建很多不同对象的实例,会比较麻烦,此时就尝试用抽象工厂模式,将使用和创建分离开来。

2、针对问题的设计要素:

产品的抽象类或接口(多个) + 产品实现类(多个)

  • 一个访问用户表抽象类或接口;
  • 一个访问部门表抽象类或接口;
  • 针对 访问数据库A里的用户表 和 访问数据库B里的用户表 的实现类各一个;
  • 针对 访问数据库A里的部门表 和 访问数据库B里的部门表 的实现类各一个;

工厂的抽象类或接口(单个) + 工厂的实现类(多个)

  • 一个用来创建连接数据库工厂的抽象类或接口;
  • 一个用来创建访问数据库A的实例对象的工厂;
  • 一个用来创建访问数据库B的实例对象的工厂。

 (注:先挖个坑,有时候可能不确定应该抽象哪个,那就无脑将那个相对不容易变化的和容易变化的分别抽象出来再进行分析就行。但实际上我相关经验很少,我也不知道怎么样才算更好,像本例是将访问用户表和访问部门表抽象出来当接口,但感觉反着来抽象出数据库A和数据库B当接口也一样。具体怎么样的抽象更好我目前也是菜鸟还不知道该怎么回答,等我以后知道答案了一定会填这个坑的。

不过说这么多,也请大家放心向下看,本例我有借鉴一些教材书,这样子是没有问题的。之所以加了这个注,是想到可能有人会想问这个问题,为什么要这样定义,所以才在此说明。)

 3.2、对象之间的关系用UML图表示如下:

 

3.3、Java实现代码如下(建议你在本地试一下,加深印象):

用户bean(举例就默认为空了,也不会影响到本例运行):

public class User {//用户表里的属性和字段
}

部门bean(举例就默认为空了,也不会影响到本例运行):

public class Department {//部门表里的属性和字段
}

访问用户表接口:

public interface IUser {public void insertUser(User user);//添加public User selectUserById(int id);//查找
}

 访问部门表接口:

public interface IDepartment {public void insertDepartment(Department department);//添加public Department selectDepartmentById(int id);//查找
}

用来访问数据库A里的用户表的类:

public class DatabaseAUser implements IUser{@Overridepublic void insertUser(User user) {System.out.println("向数据库A里的User表中增加一条数据");}@Overridepublic User selectUserById(int id) {System.out.println("根据id查询数据库A里的User表中一条数据");return null;}
}

用来访问数据库B里的用户表的类:

public class DatabaseBUser implements IUser{@Overridepublic void insertUser(User user) {System.out.println("向数据库B里的User表中增加一条数据");}@Overridepublic User selectUserById(int id) {System.out.println("根据id查询数据库B里的User表中一条数据");return null;}
}

用来访问数据库A里的部门表的类:

public class DatabaseADepartment implements IDepartment {@Overridepublic void insertDepartment(Department department) {System.out.println("向数据库A里的Department表中增加一条数据");}@Overridepublic Department selectDepartmentById(int id) {System.out.println("根据id查询数据库A里的Department表中一条数据");return null;}
}

用来访问数据库B里的部门表的类:

public class DatabaseBDepartment implements IDepartment {@Overridepublic void insertDepartment(Department department) {System.out.println("向数据库B里的Department表中增加一条数据");}@Overridepublic Department selectDepartmentById(int id) {System.out.println("根据id查询数据库B里的Department表中一条数据");return null;}
}

 工厂接口:

public interface IFactory {public IUser createUserConnect();//创建User表的访问连接实例public IDepartment createDepartmentConnect();//创建Department表的访问连接实例
}

创建数据库A的访问实例的工厂:

public class DatabaseAFactory implements IFactory {@Overridepublic IUser createUserConnect() {return new DatabaseAUser();}@Overridepublic IDepartment createDepartmentConnect() {return new DatabaseADepartment();}
}

创建数据库B的访问实例的工厂:

public class DatabaseBFactory implements IFactory {@Overridepublic IUser createUserConnect() {return new DatabaseBUser();}@Overridepublic IDepartment createDepartmentConnect() {return new DatabaseBDepartment();}
}

 主程序(发起请求的类):

public class Main {public static void main(String[] args) {User user = new User();Department department = new Department();IFactory factoryA = new DatabaseAFactory();//创建数据库A连接实例的工厂IUser iUserA = factoryA.createUserConnect();iUserA.insertUser(user);//给数据库A的用户表增加数据iUserA.selectUserById(1);//查询数据库A的用户表里的数据IDepartment iDepartmentA = factoryA.createDepartmentConnect();iDepartmentA.insertDepartment(department);//给数据库A的部门表增加数据iDepartmentA.selectDepartmentById(1);//查询数据库A的部门表里的数据System.out.println("==========分界线==========");IFactory factoryB = new DatabaseBFactory();//创建数据库B连接实例的工厂IUser iUserB = factoryB.createUserConnect();iUserB.insertUser(user);//给数据库B的用户表增加数据iUserB.selectUserById(1);//查询数据库B的用户表里的数据IDepartment iDepartmentB = factoryB.createDepartmentConnect();iDepartmentB.insertDepartment(department);//给数据库B的部门表增加数据iDepartmentB.selectDepartmentById(1);//查询数据库B的部门表里的数据}
}

在Java中还可以使用反射+配置文件进一步简化设计,可以把工厂压缩到只有一个,这里就不再举例了,可以把上面的Java例子复制到你本地,运行main函数试一下加深理解。这些代码都是我自己学习的时候根据一些教材手敲的,不存在bug可以直接运行。

如果觉得本文还不错,就请点个赞吧!如果有建议,也请评论指教和讨论!

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

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

相关文章

每日5题Day8 - LeetCode 36 - 40

每一步向前都是向自己的梦想更近一步,坚持不懈,勇往直前! 第一题:36. 有效的数独 - 力扣(LeetCode) 题目要求我们进行判断,我们不需要自己填写,所以要一个标志位,来看当…

Go源码--sync库(1)sync.Once和

简介 这篇主要介绍 sync.Once、sync.WaitGroup和sync.Mutex sync.Once once 顾名思义 只执行一次 废话不说 我们看源码 英文介绍直接略过了 感兴趣的建议读一读 获益匪浅 其结构体如下 Once 是一个严格只执行一次的object type Once struct {// 建议看下源码的注解&#xf…

首个“软件供应链安全”国家标准正式发布!ToB企业震荡,影响90%开发者

​近日,由开源网安深度参与编制的GB/T 43698-2024《网络安全技术 软件供应链安全要求》和GB/T 43848-2024《网络安全技术 软件产品开源代码安全评价方法》两项国家标准正式发布。 GB/T 43698-2024《网络安全技术 软件供应链安全要求》,是国内首个面向软件…

Linux .eh_frame section以及libunwind

文章目录 前言一、LSB二、The .eh_frame section2.1 简介2.2 The Common Information Entry Format2.1.1 Augmentation String Format 2.3 The Frame Description Entry Format 三、The .eh_frame_hdr section四、libunwind五、基于Frame Pointer和基于unwind 形式的栈回溯比较…

双向链表C++,C#,Java版,这些程序大多已经过测试,一直在用。

先C版吧&#xff0c;我最先用的是C#,后来是Java&#xff0c;后来改用C版的&#xff0c;因为现在一直在用C&#xff0c;单链 表一直没写上去&#xff0c;因为我很少用&#xff0c;用的是双链表。 执行代码例子1&#xff1a; int main() { _DList<_string> s…

9.STL中list的常见操作(图文并茂)

目录 1.list的介绍及使用 1.1.list的构造 1.2 list iterator的使用 1.3. list capacity 1.4.list modifiers 1.5.list的迭代器失效 1.list的介绍及使用 list介绍 &#xff0c;可以通过以下图直观的感受到 vector 和 list 的区别 Vector 插入代价高&#xff0c;但便于排…

力扣HOT100 - 72. 编辑距离

解题思路&#xff1a; 动态规划 class Solution {public int minDistance(String word1, String word2) {int n1 word1.length();int n2 word2.length();int[][] dp new int[n1 1][n2 1];for (int j 1; j < n2; j) dp[0][j] dp[0][j - 1] 1;for (int i 1; i < …

《艺术大观》知网艺术刊:可加急, 出刊上网快

《艺术大观》 《艺术大观》征文通知 《艺术大观》期刊诚邀学者、艺术家和文化工作者积极投稿&#xff0c;共同探索艺术领域的前沿问题&#xff0c;促进学术交流和艺术创作的发展。我们欢迎各类艺术形式的研究与评论&#xff0c;包括但不限于绘画、雕塑、音乐、舞蹈、戏剧、电…

【数据结构】排序详解(希尔排序,快速排序,堆排序,插入排序,选择排序,冒泡排序)

目录 0. 前情提醒&#xff1a; 1. 插入排序 1.1 基本思想&#xff1a; 1.2 直接插入排序 实现步骤&#xff1a; 动图演示&#xff1a; 特性总结&#xff1a; 代码实现&#xff1a; 1.3 希尔排序&#xff08;缩小增量排序&#xff09; 基本思想&#xff1a; 步骤演示&…

AI大模型如何赋能智能座舱

AI 大模型如何赋能智能座舱 从上海车展上&#xff0c;我们看到由于智能座舱配置性价比较高&#xff0c;已经成为车企的核心竞争点之一&#xff0c;随着座舱硬件规模化装车&#xff0c;蔚小理、岚图、极狐等新势力开始注重座舱多模态交互&#xff0c;通过集成语音/手势/触控打造…

Leetcode—2769. 找出最大的可达成数字【简单】

2024每日刷题&#xff08;139&#xff09; Leetcode—2769. 找出最大的可达成数字 实现代码 class Solution { public:int theMaximumAchievableX(int num, int t) {return num t * 2;} };运行结果 之后我会持续更新&#xff0c;如果喜欢我的文章&#xff0c;请记得一键三连…

【实战】SpringBoot整合Websocket、Redis实现Websocket集群负载均衡

文章目录 前言技术积累什么是Websocket什么是Redis发布订阅Redis发布订阅与消息队列的区别 实战演示SpringBoot整合WebsoketWebsoket集群负载均衡 实战测试IDEA启动两台服务端配置nginx负载均衡浏览器访问模拟对话 前言 相信很多同学都用过websocket来实现服务端主动向客户端推…

【知识蒸馏】deeplabv3 logit-based 知识蒸馏实战,对剪枝的模型进行蒸馏训练

本文将对【模型剪枝】基于DepGraph(依赖图)完成复杂模型的一键剪枝 文章中剪枝的模型进行蒸馏训练 一、逻辑蒸馏步骤 加载教师模型定义蒸馏loss计算蒸馏loss正常训练 二、代码 1、加载教师模型 教师模型使用未进行剪枝&#xff0c;并且已经训练好的原始模型。 teacher_mod…

利用Python去除PDF水印

摘要 本文介绍了如何使用 Python 中的 PyMuPDF 和 OpenCV 库来从 PDF 文件中移除水印&#xff0c;并将每个页面保存为图像文件的方法。我们将深入探讨代码背后的工作原理&#xff0c;并提供一个简单的使用示例。 导言 简介&#xff1a;水印在许多 PDF 文件中都很常见&#x…

全国数据库管理系统设计赛-人大金仓内核实训安排正式发布

作为数据库领域国家队&#xff0c;人大金仓积极响应国家战略&#xff0c;通过赛题设计、内核技术支撑及赛前培训等多方面&#xff0c;大力支持全国大学生计算机系统能力大赛-数据库管理系统设计大赛成功举办。目前第二届全国大赛正在火热报名中&#xff0c;各种奖项等你来拿&am…

《web应用设计》第八次作业

我的小组长是姚若希&#xff0c;我们组课程设计的题目是&#xff1a;学生管理系统 &#xff0c;我认领的功能模块是&#xff1a;课程管理 2.查询并分页

只需三步,即可配置HTTPS跳转

HTTPS&#xff08;全称&#xff1a;Hyper Text Transfer Protocol over Secure Socket Layer&#xff09;&#xff0c;是以安全为目标的HTTP通道&#xff0c;简单讲是HTTP的安全版。通过SSL/TLS协议对数据进行加密&#xff0c;保证了数据传输的安全&#xff0c;防止数据被截获、…

UWB论文:Introduction to Impulse Radio UWB Seamless Access Systems(2):脉冲;超宽带;测距;定位

3) 测距/接收器 像全球定位系统&#xff08;GPS&#xff09;这样的系统依赖于单向测距One Way Ranging&#xff08;OWR&#xff09;&#xff0c;其中多个卫星&#xff08;代表固定节点&#xff0c;称为锚点anchors&#xff09;定期传输同步的无线电数据包集合&#xff0c;这允许…

sh控制台输入文字多行 按“# ꧂ ꧁”结束

如果在Unix shell中输入多行文字&#xff0c;那么这样操作&#xff1a; 1. 打开您的终端&#xff08;Terminal&#xff09;。 2. 输入您的文字&#xff0c;每行文字后按回车键。 3. 当您完成输入所有文字后&#xff0c;输入“# ꧂ ꧁”然后按回车键&#xff0c;表示输入结束。…

将Surface的分辨率减半以省电(二合一本\笔记本电脑适用)

【完全自定义分辨率教程】这篇教程用于将Surface之类的高分屏&#xff08;高分辨率&#xff09;的二合一本或笔记本等的分辨率调整为原来的一半&#xff0c;以实现省电等目的。 下载CRU&#xff08;Custom Resolution Utility&#xff09;解压后&#xff0c;打开CRU.exe选择当…