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

news2024/12/23 22:08:07

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的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可以直接运行。

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

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

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

相关文章

2024年贵州特岗教师招聘报名流程,速速查收哦!

2024年贵州特岗教师招聘报名流程,速速查收哦!

DolphinDB 携手九鞅科技,助力固收投研效能飞跃

随着金融市场开放的广度与深度不断拓宽,金融产品呈现出多样化的发展态势,其中债券投资组合凭借其低风险性、高流动性与稳健的收益表现,逐渐成为投资理财领域备受瞩目的焦点。投资经理不仅需要了解哪些债券值得投资,更要对债券投资…

MySQL日常联系---20万数据的存储过程(一)。

一、创建DDL和DML CREATE TABLE student (id INT PRIMARY KEY AUTO_INCREMENT,createDate DATE NOT NULL,userName VARCHAR(255) NOT NULL,phone VARCHAR(15),age INT,sex CHAR(1), -- 假设M代表男,F代表女introduce TEXT );INSERT INTO student (createDate, user…

二叉树创建与销毁操作详解

目录 一、通过前序遍历的数组构建二叉树 1.1 递归思路 1.2 递归分支图 1.3 递归栈帧图 1.4 C语言实现 二、二叉树的销毁 2.1 递归思路 2.2 递归分支图 2.3 递归栈帧图 2.4 C语言实现 一、通过前序遍历的数组构建二叉树 牛客网链接:二叉树遍历_牛客题霸_牛…

2024年618购物狂欢节即将来袭!精选五款超值入手数码好物!

618购物狂欢盛宴即将落幕,是时候展现我们的购物智慧了!在追求价格优惠的同时,我们更应看重商品的品质与实用性。面对琳琅满目的选择,如何筛选出真正值得拥有的好物呢?为了让大家的购物之旅更加轻松愉快,以下…

想学接口测试,不知道那个工具适合?

引言: 接口测试在软件开发中扮演着至关重要的角色,它可以帮助我们验证系统的功能、性能和安全性。而选择适合的工具是进行接口测试的重要一步。本文将从零开始,为你详细介绍如何选择合适的工具,并提供规范的指导。 一、了解接口…

通过cmd命令行使用用3dmax自带的vray渲染

有时调试需要使用vray渲染vrscene文件看效果,只装有3dmax下可以使用自带vray渲染,在3dmax的渲染日志里面看自带引擎路径 使用命令行进入到此目录 执行命令指定vr文件即可看到效果,如:vray.exe -sceneFile“C:\test15\202405241…

Jetbrain | IDEA的启动logo替换成可爱的vtuber-logo

看了这个,好可爱 【上Github热榜了!当编程语言的Logo变得可爱起来~】 又看了这个 光速整活,强啊 看到很多人整IDEA的logo包括我自己,都不是特别方便的搞,我就直接把文件放在绑定资源里直接下吧 然后直接找到本体的安…

HTML+JavaScript+CSS:爱心代码

1、创建heart.js文件 // 定义画布的宽度和高度,以及画布的中心点坐标 const CANVAS_WIDTH 640; const CANVAS_HEIGHT 480; const CANVAS_CENTER_X CANVAS_WIDTH / 2; const CANVAS_CENTER_Y CANVAS_HEIGHT / 2;// 定义图像的放大因子,用于调整爱心的…

【译】组复制和 Percona XtraDB 集群: 常见操作概述

原文地址:Group Replication and Percona XtraDB Cluster: Overview of Common Operations 在这篇博文中,我将概述使用 MySQL Group Replication 8.0.19(又称 GR)和 Percona XtraDB Cluster 8 (PXC)(基于 Galera&…

Wireshark 4.2.5:发现 QUIC 和 VXLAN 协议的新功能

Wireshark 是一种先进且广泛使用的网络协议分析仪,最近发布了新版本 4.2.5,它提供了许多新功能和改进。 Wireshark 4.2.5 发行说明 什么是 Wireshark? Wireshark 是世界上最流行的网络协议分析器。它用于故障排除、分析、开发和教育。 Wiresh…

汇编:函数以及函数参数传递

汇编语言中的函数(或过程)是指一段可以被调用和执行的代码块;它们用于组织和重用代码,并使程序结构更加清晰;由于汇编语言没有高层次语言的语法糖,编写和调用函数涉及直接的堆栈操作和寄存器管理&#xff1…

《中国企业报》集团数字产业发展研究院介绍

《中国企业报》集团数字产业发展研究院(以下简称“中企数研院”),隶属于《中国企业报》集团管理。“中企数研院”致力于“数字经济产业化发展战略”大背景下,以“县域数字经济”、“企业数字化转型”及“数字人民币”推广等发展方…

Vue3实战笔记(35)—集成炫酷的粒子特效

文章目录 前言一、vue3使用tsparticles二、使用步骤总结 前言 学习一个有趣炫酷的玩意开心一下。 tsparticles,可以方便的实现各种粒子特效。支持的语言框架也是相当的丰富. 官网:https://particles.js.org/ 一、vue3使用tsparticles 先来个vue3使用…

大语言模型的工程技巧(四)——梯度检查点

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型:从线性回归到通用人工智能》,欢迎有兴趣的读者多多支持。 本文将讨论如何利用梯度检查点算法来减少模型在训练时候(更准确地说是运行反向传播算法时)的内存开支。…

【Spring Cloud】全面解析服务容错中间件 Sentinel 持久化两种模式

文章目录 推送模式本地文件持久化(拉模式)配置yml编写处理类添加配置演示 配置中心持久化(推模式)修改nacos在sentinel中生效引入依赖配置文件 修改sentinel在nacos中生效下载源码更改代码演示 总结 推送模式 Sentinel 规则的推送…

网络安全快速入门(十五) linux用户管理

14.1 前言 前面我们已经大概了解了Linux的网络链接,今天我们来看看Linux用户管理的一些基础操作,话不多说,我们来开始吧!! 14.2 用户的基础知识 我们先了解一些有关linux用户的一些基础知识,我们从Linux用…

告别传统,拥抱未来——上门回收小程序引领变革

随着科技的飞速发展,我们生活的方方面面都在经历着前所未有的变革。在环保和可持续发展的背景下,传统的废品回收方式已经难以满足现代社会的需求。而上门回收小程序的出现,正以其便捷、高效的特点,引领着废品回收行业的变革。 一、…

Threejs路径规划_基于A*算法案例完整版

上节利用了A*实现了基础的路径规划,这节把整个功能完善好,A*算法一方面是基于当前点找到可以到达的点,计算从出发点到此点,以及此点到目的地的总成本,比较出最小的那个,再用最小成本的点继续找到它可以到达…

LabVIEW与串口通讯在运行一段时间后出现数据接收中断的问题

这些问题可能与硬件、软件或通信协议有关。以下是详细的原因分析和可能的解决方案: 一、硬件原因 串口线缆或接口问题: 由于长时间使用,串口线缆可能出现接触不良或损坏。接口松动也可能导致通讯中断。 解决方案:检查并更换串口…