设计模式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{
    @Override
    public void insertUser(User user) {
        System.out.println("向数据库A里的User表中增加一条数据");
    }

    @Override
    public User selectUserById(int id) {
        System.out.println("根据id查询数据库A里的User表中一条数据");
        return null;
    }
}

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

public class DatabaseBUser implements IUser{
    @Override
    public void insertUser(User user) {
        System.out.println("向数据库B里的User表中增加一条数据");
    }

    @Override
    public User selectUserById(int id) {
        System.out.println("根据id查询数据库B里的User表中一条数据");
        return null;
    }
}

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

public class DatabaseADepartment implements IDepartment {
    @Override
    public void insertDepartment(Department department) {
        System.out.println("向数据库A里的Department表中增加一条数据");
    }

    @Override
    public Department selectDepartmentById(int id) {
        System.out.println("根据id查询数据库A里的Department表中一条数据");
        return null;
    }
}

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

public class DatabaseBDepartment implements IDepartment {
    @Override
    public void insertDepartment(Department department) {
        System.out.println("向数据库B里的Department表中增加一条数据");
    }

    @Override
    public 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 {
    @Override
    public IUser createUserConnect() {
        return new DatabaseAUser();
    }

    @Override
    public IDepartment createDepartmentConnect() {
        return new DatabaseADepartment();
    }
}

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

public class DatabaseBFactory implements IFactory {
    @Override
    public IUser createUserConnect() {
        return new DatabaseBUser();
    }

    @Override
    public 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可以直接运行。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker+nginx部署SpringBoot+vue前后端分离项目(保姆及入门指南)

前后分离项目部署 项目回顾工具上线准备1、win1.1、前端1.2、后端 2、linux环境2.1、安装docker2.2、安装docker compose2.3、编写Dockerfile文件2.4、编写docker-compose.yml文件2.5、修改application-pro.yml2.6、准备好nginx的挂载目录和配置2.7、部署后端服务 项目回顾 书…

Pod容器资源限制和探针

目录 一、资源限制 1.Pod和容器的资源请求和限制 2.CPU 资源单位 案例一 案例二 二、健康检查,又称为探针(Probe) 1.探针的三种规则 2.Probe支持三种检查方法 3.探测获得的三种结果 案例一:exec 案例二:htt…

C语言/数据结构——每日一题(有效的括号)

一.前言 如果想要使用C语言来解决这道题——有效的括号:https://leetcode.cn/problems/valid-parentheses/description/我们必须要借用上一篇我们所讲的内容——栈的实现:https://blog.csdn.net/yiqingaa/article/details/138923750?spm1001.2014.3001.…

LLM实战:当网页爬虫集成gpt3.5

1. 背景 最近本qiang~关注了一个开源项目Scrapegraph-ai,是关于网页爬虫结合LLM的项目,所以想一探究竟,毕竟当下及未来,LLM终将替代以往的方方面面。 这篇文章主要介绍下该项目,并基于此项目实现一个demo页面&#x…

【linux】深入了解线程池:基本概念与代码实例(C++)

文章目录 1. 前言1.1 概念1.2 应用场景1.3 线程池的种类1.4 线程池的通常组成 2. 代码示例2.1 log.hpp2.2 lockGuard.hpp① pthread_mutex_t 2.3 Task.hpp2.4 thread.hpp2.5 threadPool.hpp① 基本框架② 成员变量③ 构造函数④ 其余功能函数: main.cc结果演示 完整…

车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文

系列文章目录 车载网络测试实操源码_使用CAPL脚本解析hex、S19、vbf文件 车载网络测试实操源码_使用CAPL脚本对CAN报文的Counter和CRC进行实时监控 车载网络测试实操源码_使用CAPL脚本模拟发送符合协议要求(Counter和CRC)的CAN报文 车载网络测试实操源码_使用CAPL脚本实现安全…

Go语言实现人脸检测(Go的OpenCV绑定库)

文章目录 OpenCVGithub官网安装环境变量 Go的OpenCV绑定库Github文档安装搜索视频设备ID显示视频检测人脸 OpenCV Github https://github.com/opencv/opencv/ 官网 https://opencv.org/ 安装 brew install opencv brew upgrade opencv安装目录 cd /usr/local/opt/opencv…

做OZON怎么选择物流,OZON物流Xingyuan

随着跨境电商的蓬勃发展,OZON作为俄罗斯领先的电商平台,吸引了大量中国卖家入驻。然而,物流作为跨境电商的关键环节,其选择对于卖家来说至关重要。本文将围绕“做OZON怎么选择物流”这一问题,深度解析OZON物流Xingyuan…

我爱我家:租赁下位替代买房,能行吗?

我爱我家,凭什么五天四板? 上周五的楼市组合拳出台后,地产板块迎来高潮。 这其中最火的不是我们常说的“招宝万金”,而是——我爱我家。 五天四板,一个月不到,股价轻松翻翻。 公司有什么变化吗&#xff1…

Android ART 虚拟机简析

源码基于:Android U 1. prop 名称选项名称heap 变量名称功能 dalvik.vm.heapstartsize MemoryInitialSize initial_heap_size_ 虚拟机在启动时,向系统申请的起始内存 dalvik.vm.heapgrowthlimit HeapGrowthLimit growth_limit_ 应用可使用的 max…

3dmax安装不完整Revit Interoperability

3dmax安装不完整Revit Interoperability 1.错误如图 2.在Autoremove界面中,点击扩展选项。 3.在扩展选项中,寻找并点击"1402 1406修复"。 4.根据软件指引,执行修复操作。Autoremove将自动修复无法打开注册表的问题。 如图 修…

[智能AI摄像头]使用docker搭建RV1126开发环境

创建ubuntu docker 创建dockerfile # 设置基础镜像为Ubuntu 18.04FROM ubuntu:20.04# 设置作者信息MAINTAINER warren "2016426377qq.com"# 设置环境变量,用于非交互式安装ENV DEBIAN_FRONTENDnoninteractive# 备份源列表文件RUN cp -a /etc/apt/source…

基于SSM的大学生兼职管理系统

基于SSM的大学生兼职管理系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringSpringMVCMyBatis工具:IDEA/Ecilpse、Navicat、Maven 系统展示 登录界面 企业界面 前台学生界面 管理员界面 摘要 随着大学生兼职市场的日益繁…

LeetCode674:最长连续递增序列

题目描述 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定&#xff0c;如果对于每个 l < i < r&#xff0c;都有 nums[i] < nums…

必应bing国内广告开户首充和开户费是多少?

微软必应Bing作为国内领先的搜索引擎之一&#xff0c;其广告平台凭借其精准的投放、高效的数据分析和广泛的用户覆盖&#xff0c;已成为众多企业的首选。 根据最新政策&#xff0c;2024年必应Bing国内广告开户预充值金额设定为1万元人民币起。这一调整旨在确保广告主在账户初始…

智研未来,直击 AI DevOps,阿里云用户交流日杭州站来啦!

在这个技术日新月异的时代&#xff0c;云上智能化 DevOps 正以前所未有的速度推动企业创新边界&#xff0c;重塑软件开发的效率与品质。 为深入探索这一变革之路&#xff0c;诚邀您参与我们的专属闭门技术沙龙&#xff0c;携手开启一场关于云上智能化 DevOps 的挑战、实践与未…

Vue学习笔记2——创建一个Vue项目

Vue项目 1、创建一个Vue项目2、Vue项目的目录结构3、模版语法4、属性绑定5、条件渲染 1、创建一个Vue项目 vue官方文档&#xff1a; https://cn.vuejs.org/打开命令行界面&#xff08; “winR"再输入"cmd”&#xff09;&#xff0c;切换位置到指定的位置创建vue项目…

通胀担忧仍存,美联储降息预期或又推迟

KlipC报道&#xff1a;周三&#xff0c;美联储公布4月30日至5月1日政策会议纪要&#xff0c;会议纪要显示美联储对通胀仍感到担忧&#xff0c;将更长时间维持利率不变&#xff0c;必要时进一步收紧政策。 尽管在前不久公布的4月CPI数据显示通胀有所缓解&#xff0c;但是被认为…

高刚性滚柱直线导轨有哪些优势?

滚柱导轨是机械传动系统中用于支持和引导滑块或导轨的装置&#xff0c;承载能力较高、刚性强及高精度等特点。特别适用于大负载和高刚性的工业设备&#xff0c;如机床、数控机床等设备&#xff0c;这些优势使其在工业生产和机械设备中得到了广泛的应用。 1、高精度&#xff1a;…

如何用java做一个模拟登录画面

要求&#xff1a; 实现registerAction方法中的注册逻辑。实现login方法中的登录逻辑&#xff0c;确保只有当用户名和密码都正确时才返回true。实现好友管理功能&#xff0c;包括添加好友、删除好友、查看好友列表。确保所有的文件操作&#xff08;如读取和写入credentials.txt…