多数据库切换?设计模式--抽象工厂引导下思路

news2025/1/23 17:30:32

缘起

某日,部门Leader找到小明:“小明,我们公司不是用的SQL Server的数据库吗,但是后面可能会改,比如去使用Access或Mysql或其他的,你觉得该怎么去设计这个代码呢?”

小明一脸所思,陷入了思考中…

Leader:“或者你先这样,先把最基本的访问数据库的示例写一下。”

小明听后,几分钟后代码出炉。

User类

public class User {
    
    private int id;
    private String name;
	..getter/setter
}

SqlServerUser类,用于操作User表,假设只有新增用户和查询用户的方法。

public class SqlServerUser {
    
    public void insert(User user) {
        System.out.println("Sql server插入了一条用户数据");
    }
    
    public void getUser(int id) {
        System.out.println("Sql server查询一条用户数据");
    }
    
}
  • 客户端调用
User user = new User();
SqlServerUser sqlServerUser = new SqlServerUser();
sqlServerUser.insert(user);

sqlServerUser.getUser(1);

改造

Leader:“你看这里,是不是最基本的实现了Sql server数据库的操作,假如换成别的你还要改一大堆对吧,那么你是不是可以把每个数据库的操作都封装起来呢,而且它们所有数据库执行的操作结果都是一致的。当我需要哪个数据库的操作时,就实例化哪个数据库的实例去使用就完事儿了”

小明听后,立即想到了之前的工厂模式。

在这里插入图片描述

  • IUser接口:用户客户端访问,解除与具体数据库访问的耦合
public interface IUser {
    void insert(User user);
    User getUser(int id);
}
  • SqlServerUser:用于访问Sqlserver的User
public class SqlServerUser implements IUser{

    public void insert(User user) {
        System.out.println("Sql server插入了一条用户数据");
    }
    public User getUser(int id) {
        System.out.println("Sql server查询一条用户数据");
        return null;
    }
}
  • AccessUser:用于Access的User
public class AccessUser implements IUser{

    public void insert(User user) {
        System.out.println("Access插入了一条用户数据");
    }
    public User getUser(int id) {
        System.out.println("Access查询一条用户数据");
        return null;
    }
}
  • IFactory:定义一个创建访问User表对象的抽象的工厂接口
public interface IFactory {

    IUser createUser();
}
  • SqlserverFactory:实现IFactory接口,实例化SqlServerUser
public class SqlServerFactory implements IFactory {
    @Override
    public IUser createUser() {
        return new SqlServerUser();
    }
}
  • AccessFactory:实现IFactory接口,实例化AccessUser
public class AccessFactory implements IFactory {

    @Override
    public IUser createUser() {
        return new AccessUser();
    }
}
  • 客户端调用
User user = new User();
IFactory factory = new SqlServerFactory();
IUser iUser = factory.createUser();

iUser.insert(user);
iUser.getUser(1);

再增部门

Leader看后,点了点头,“假如我再新增一个部门表的数据库操作呢”

小明继续编码中。。。

  • 部门
public class Dept {
    private int id;
    private String name;
}
  • IDept
public interface IDept {
    void insert(Dept dept);
    Dept getDept(int id);
}
  • SqlserverDept:访问Sqlserver的部门数据
public class SqlServerDept implements IDept{

    @Override
    public void insert(Dept dept) {
        System.out.println("Sqlserver 新增一条部门数据");
    }

    @Override
    public Dept getDept(int id) {
        System.out.println("Sqlserver查询一条部门数据");
        return null;
    }
}
  • AccessDept
public class AccesssDept implements IDept{

    @Override
    public void insert(Dept dept) {
        System.out.println("Access 新增一条部门数据");
    }

    @Override
    public Dept getDept(int id) {
        System.out.println("Access查询一条部门数据");
        return null;
    }
}
  • IFactory
public interface IFactory {

    IUser createUser();

    IDept createDept();
}
  • SqlServerFactory
public class SqlServerFactory implements IFactory {

    @Override
    public IUser createUser() {
        return new SqlServerUser();
    }

    @Override
    public IDept createDept() {
        return new SqlServerDept();
    }
}
  • AccessFactory
public class AccessFactory implements IFactory {

    @Override
    public IUser createUser() {
        return new AccessUser();
    }

    @Override
    public IDept createDept() {
        return new AccesssDept();
    }
}
  • 客户端
User user = new User();
IFactory factory = new SqlServerFactory();
IUser iUser = factory.createUser();

iUser.insert(user);
iUser.getUser(1);

IDept dept = factory.createDept();
dept.insert(new Dept());
dept.getDept(1);

Leader:“很好,这样子后面如果有很多表,也只需要多增加一些类就行了,只要能把代码灵活性提高,多增加一些类也没有啥问题。”

而且你这种代码结构实际是使用了一种抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

像上面我们的IUser和IDept其实就是两中产品的抽象,那么实际的SqlServerUser、SqlServerDept、AccessUser、AccessDept就是他们的具体分类的实现。IUser和IDept实际就是两种不同的产品分类,然后具体的产品实现由子类进行衍生。

IFactory类就是我们的抽象工厂类了,它里面应该包含所有的产品创建的抽象方法。那么SqlserverFactory和AccessFactory就是两种产品的工厂,具体生成哪种产品由它们来决定。

优缺点

优点:最大的好处是易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。

缺点:显而易见,每次如果有一个新的表,至少需要增加三个类,而且还需要改动至少三处。这样大批量的改动显然是非常丑陋的做法。

简单工厂改进抽象工厂

在这里插入图片描述

直接去除IFatory和子Factory,用DataAccess取而代之它们。

public class DataAccess { 
    private static String db = "Sqlserver";
    public static IUser createUser() {
        IUser res = null;
        switch (db) {
            case "Sqlserver":
                res = new SqlServerUser();
                break;
            case "Access":
                res = new AccessUser();
                break;
        }
        return res;
    }
    public static IDept createDept() {
        IDept res = null;
        switch (db) {
            case "Sqlserver":
                res = new SqlServerDept();
                break;
            case "Access":
                res = new AccesssDept();
                break;
        }
        return res;
    }
}
  • 客户端
User user = new User();
IUser iUser = DataAccess.createUser();

iUser.insert(user);
iUser.getUser(1);

IDept dept = DataAccess.createDept();
dept.insert(new Dept());
dept.getDept(1);

客户端中没有出现一个Sqlserver或Access的字样,将耦合度降到最低。

Tips:在DataAccess类中db字段若不想硬编码到代码中,可以在项目资源文件夹中创建一个文件,读取文件的db属性,使用反射的方式动态生成需要的SqlserverUser或其他产品对象。

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

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

相关文章

亚马逊测评的重要性和技术选择

亚马逊测评是指卖家通过各种途径,如测评平台、社区、红人等,联系到亚马逊的买家,让其对卖家的产品进行评价和留下真实的综合评价,这对于跨境电商卖家来说非常重要,因为亚马逊的排名和转化率很大程度上取决于产品的评价…

什么是数据资产化?数据怎样成为资产?怎样进入资产负债表?

财政部发布的《企业数据资源相关会计处理暂行规定》将从2024年1月1日起开始实施,为企业数据资源入表提供了基本指引,数据资产化有望迎来爆发期。什么是数据资产化,怎样让数据成为资产,成为了众多国有企业、上市公司关心的问题。 —…

应用全局的UI状态存储AppStorage

目录 1、概述 2、StorageProp 2.1、观察变化和行为表现 3、StorageLink 3.1、观察变化和行为表现 4、从应用逻辑使用AppStorage和LocalStorage 5、从UI内部使用AppStorage和LocalStorage 6、不建议借助StorageLink的双向同步机制实现事件通知 6.1、推荐的事件通知方式…

KiCad 类型为电源输出和电源输出的引脚已连接

环境: KiCad 版本:7.0.6 操作系统版本:Win10 错误描述: KiCad 原理图 ERC 检查啊出现错误,错误提示下: 类型为电源输出和电源输出的引脚已连接。 错误原因: 电源输出和电源输出连接到了一起…

电商裂变营销的新策略:工会排队

电商行业已经发展了很多年了,一些基本的营销手段大家也是见识过的,比如:打折、满减、618、双十一、双十二等等。但是很多人把东西都屯到这种节日下单,算下来发现根本没便宜多少,有的反而更贵了,因为这是商家…

实在智能斩获钛媒体2023全球创新评选科技类「 大模型创新应用奖」

近日,历时三天的钛媒体2023 T-EDGE全球创新大会以“新视野新链接”为主题在北京隆重举办。作为科创领域全新高度的年度盛事,大会吸引了AI各产业链近百位海内外创投人、尖端企业家、商业领袖和国际嘉宾齐聚一堂,围绕新一轮AI革命、智慧数字化、…

AI时代Python量化交易实战:ChatGPT引领新时代

文章目录 《AI时代Python量化交易实战:ChatGPT让量化交易插上翅膀》关键点内容简介作者简介购买链接 《AI时代架构师修炼之道:ChatGPT让架构师插上翅膀》关键点内容简介作者简介 赠书活动 《AI时代Python量化交易实战:ChatGPT让量化交易插上翅…

【Mubert AI】快速自动生成免版税音乐

关于Mubert Mubert Mubert是一款很专业音乐创作工具,许多创作者和艺术家都在用它。 生成的音乐质量很高,使用方法也非常简单。 开始制作音乐 在主页选择“立即生成曲目”,无需登录立刻就可以进入音乐生成模式。 你可以根据需要&#xff0…

【模式识别】探秘判别奥秘:Fisher线性判别算法的解密与实战

​🌈个人主页:Sarapines Programmer🔥 系列专栏:《模式之谜 | 数据奇迹解码》⏰诗赋清音:云生高巅梦远游, 星光点缀碧海愁。 山川深邃情难晤, 剑气凌云志自修。 目录 🌌1 初识模式识…

自动生成数控加工的轨迹刀具轨迹阿基米德螺旋线(3D)

文章目录 1. 阿基米德螺旋线2. 生成步骤目标: 基于点云自动生成阿基米德螺旋线轨迹点 针对的是半球形模型效果 1. 阿基米德螺旋线 阿基米德螺旋线(Archimedean spiral)是一种数学曲线,由古希腊数学家阿基米德(Archimedes)在公元前225年左右首次研究和描述。这条曲线的方…

Ubuntu 常用命令之 clear 命令用法介绍

📑Linux/Ubuntu 常用命令归类整理 clear命令在Ubuntu系统下用于清除终端屏幕的内容。这个命令没有任何参数,它的主要作用就是清理终端屏幕上的所有信息,使得屏幕看起来像是新打开的一样。 使用clear命令非常简单,只需要在终端中…

微前端样式隔离、sessionStorage、localStorage隔离

1、样式隔离 前端样式不隔离,会产生样式冲突的问题,这个点在qiankun也存在 子应用1修改一个样式 button {background: red!important; }其它应用也会受到影响 qiankun的css隔离方案(shadow dom) shadow …

MySQL报错:1366 - Incorrect integer value: ‘xx‘ for column ‘xx‘ at row 1的解决方法

我在插入表数据时遇到了1366报错,报错内容:1366 - Incorrect integer value: Cindy for column name at row 1,下面我演示解决方法。 根据上图,原因是Cindy’对应的name字段数据类型不正确。我们在左侧找到该字段所在的grade_6表&…

分布式系统架构设计之分布式数据管理

随着互联网时代的不断发展,分布式系统架构成为支撑大规模用户和高并发访问的基础。在构建分布式系统时,分布式系统有着一系列的要求以及对应的核心技术,涉及到数据管理、通信安全性、性能优化、可扩展性设计以及架构演进与版本管理等很多方面…

[MTCTF 2022]easypickle

题目给了源码 import base64 import pickle from flask import Flask, session import os import randomapp Flask(__name__) app.config[SECRET_KEY] os.urandom(2).hex()app.route(/) def hello_world():if not session.get(user):session[user] .join(random.choices(&q…

【前端】前后端通信方法与差异(未完待续)

系列文章 【Vue】vue增加导航标签 本文链接:https://blog.csdn.net/youcheng_ge/article/details/134965353 【Vue】Element开发笔记 本文链接:https://blog.csdn.net/youcheng_ge/article/details/133947977 【Vue】vue,在Windows IIS平台…

Linux--编写系统服务脚本

编写一个名为myprog的系统服务脚本,通过位置变量s1指定的start、stop、restart、status控制参数,分别用来启动、停止、重启sleep进程,以及查看sleep进程的状态。其中,命令sleep用来暂停指定秒数的时间,这里仅用做测试&…

最新ChatGPT网站系统源码+AI绘画系统+支持GPT语音对话+详细图文搭建教程/支持GPT4.0/H5端系统/文档知识库

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统,支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

关于增强监控以检测针对Outlook Online APT活动的动态情报

一、基本内容 2023年6月,联邦民事行政部门(FCEB)在其Microsoft 365(M365)云环境中发现了可疑活动。该机构迅速向Microsoft和网络安全和基础设施安全局(CISA)报告了此情况。经过深入调查&#x…

【内存泄漏】编码实现内存泄漏检测功能

编码实现内存泄漏检测功能 使用脚本统计 meminfo 判断是否有内存泄漏 使用 bash 或 python 脚本循环抓取指定进程的 meminfo 保存到 txt 文件;使用 python 脚本解析出txt 文件中的 PSS 信息,借助 pyecharts 或其他可视化三方库将数据以折线图可视化&am…