JAVA【设计模式】抽象工厂模式

2023-11-15

一、定义

在这里插入图片描述
抽象工厂模式,类似于动态代理对象的生成工厂,集中管理各个代理对象,使用代理对象解决实际业务场景,减少代码的依赖

抽象⼯⼚模式与⼯⼚⽅法模式虽然主要意图都是为了解决,接⼝选择问题。但在实现上,抽象⼯⼚是⼀个中⼼⼯⼚,创建其他⼯⼚的模式

二、示例:

模拟场景:
很多时候初期业务的蛮荒发展,也会牵动着研发对系统的建设。
预估 QPS较低 、 系统压⼒较⼩ 、 并发访问不⼤ 、 近⼀年没有⼤动作 等等,在考虑时间投⼊成本的前提前,并不会投⼊特别多的⼈⼒去构建⾮常完善的系统。就像对 Redis 的使⽤,往往可能只要是单机的就可以满⾜现状。

但随着业务超过预期的快速发展,系统的负载能⼒也要随着跟上。原有的单机 Redis 已经满⾜不了系
统需求。这时候就需要更换为更为健壮的Redis集群服务,虽然需要修改但是不能影响⽬前系统的运
⾏,还要平滑过渡过去。

随着这次的升级,可以预⻅的问题会有;

  1. 很多服务⽤到了Redis需要⼀起升级到集群。
  2. 需要兼容集群A和集群B,便于后续的灾备。
  3. 两套集群提供的接⼝和⽅法各有差异需要做适配
  4. 不能影响到⽬前正常运⾏的系统。

传统硬编码方式(都在一个类里面实现,多重if else嵌套使用)

定义集群接口:CacheClusterService

package com.qf.design.create.abstractfactory.tradition.cluster;

import java.util.concurrent.TimeUnit;

public interface CacheClusterService {

    String get(final String key,int redisType);

    void set(String key, String value,int redisType);

    void set(String key, String value, long timeout, TimeUnit timeUnit,int redisType);

    void del(String key,int redisType);

}

集群接口实现:CacheClusterImpl ,随着集群类型变多,if else判断也变多,需要修改以前的代码,违背了开闭原则

package com.qf.design.create.abstractfactory.tradition.cluster;


import com.qf.design.create.abstractfactory.tradition.redis.RedisUtils;
import com.qf.design.create.abstractfactory.tradition.redis.cluster.EGM;
import com.qf.design.create.abstractfactory.tradition.redis.cluster.IIR;

import java.util.concurrent.TimeUnit;

public class CacheClusterImpl implements CacheClusterService {
    private RedisUtils redisUtils=new RedisUtils();
    private EGM egm=new EGM();
    private IIR iir=new IIR();

    @Override
    public String get(String key, int redisType) {
        if (redisType==1){
            return egm.gain(key);
        }

        if (redisType==2){
            return iir.get(key);
        }

        return redisUtils.get(key);
    }

    @Override
    public void set(String key, String value, int redisType) {
        if (redisType==1){
             egm.set(key,value);
        }

        if (redisType==2){
             iir.set(key,value);
        }

        redisUtils.set(key,value);
    }

    @Override
    public void set(String key, String value, long timeout, TimeUnit timeUnit, int redisType) {
        if (redisType==1){
            egm.setEx(key,value,timeout,timeUnit);
        }

        if (redisType==2){
            iir.setExpire(key,value,timeout,timeUnit);
        }

        redisUtils.set(key,value,timeout,timeUnit);
    }

    @Override
    public void del(String key, int redisType) {
        if (redisType==1){
            egm.delete(key);
        }

        if (redisType==2){
            iir.del(key);
        }

        redisUtils.del(key);
    }
}

测试:ApiTest

package com.qf.design.create.abstractfactory.tradition.cluster;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ApiTest {
    private static Logger logger= LoggerFactory.getLogger(Logger.class);
    public static void main(String[] args) {
        CacheClusterImpl cacheCluster=new CacheClusterImpl();
        cacheCluster.set("mykey","values01",1);
        String mykey01 = cacheCluster.get("mykey", 1);
        logger.info("EGM values:"+mykey01);

        cacheCluster.set("mykey","values02",2);
        String mykey02 = cacheCluster.get("mykey", 2);
        logger.info("EGM values:"+mykey02);
    }
}

抽象工厂模式

定义缓存实现接口:ICacheAdapter

package com.qf.design.create.abstractfactory.design.workshop;

import java.util.concurrent.TimeUnit;

public interface ICacheAdapter {
    String get(final String key);

    void set(String key, String value);

    void set(String key, String value, long timeout, TimeUnit timeUnit);

    void del(String key);
}

EGMCache缓存实现接口:EGMCacheAdapter

package com.qf.design.create.abstractfactory.design.workshop.impl;

import com.qf.design.create.abstractfactory.design.workshop.ICacheAdapter;
import com.qf.design.create.abstractfactory.tradition.redis.cluster.EGM;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class EGMCacheAdapter implements ICacheAdapter {

    private EGM egm=new EGM();

    @Override
    public String get(String key) {
        return egm.gain(key);
    }

    @Override
    public void set(String key, String value) {
        egm.set(key,value);
    }

    @Override
    public void set(String key, String value, long timeout, TimeUnit timeUnit) {
        egm.setEx(key,value,timeout,timeUnit);
    }

    @Override
    public void del(String key) {
        egm.delete(key);
    }
}

IIRCache缓存实现接口:IIRCacheAdapter

package com.qf.design.create.abstractfactory.design.workshop.impl;

import com.qf.design.create.abstractfactory.design.workshop.ICacheAdapter;
import com.qf.design.create.abstractfactory.tradition.redis.cluster.IIR;

import java.util.concurrent.TimeUnit;

public class IIRCacheAdapter implements ICacheAdapter {

    private IIR iir=new IIR();

    @Override
    public String get(String key) {
        return iir.get(key);
    }

    @Override
    public void set(String key, String value) {
        iir.set(key,value);
    }

    @Override
    public void set(String key, String value, long timeout, TimeUnit timeUnit) {
        iir.setExpire(key,value,timeout,timeUnit);
    }

    @Override
    public void del(String key) {
        iir.del(key);
    }
}

JDK动态代理:JDKInvocationHandler

package com.qf.design.create.abstractfactory.design.factory;

import com.qf.design.create.abstractfactory.design.workshop.ICacheAdapter;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class JDKInvocationHandler implements InvocationHandler {
    private ICacheAdapter iCacheAdapter;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return  method.invoke(iCacheAdapter,args);
    }

    public void bind(Object obj) {
        this.iCacheAdapter= (ICacheAdapter) obj;
    }
}

JDK动态代理的实现工厂:JDKProxyFactory

package com.qf.design.create.abstractfactory.design.factory;

import java.lang.reflect.Proxy;

public class JDKProxyFactory {
    public static Object getProxyInstance(Object obj){  //被代理的对象
        JDKInvocationHandler myInvocationHandler=new JDKInvocationHandler();
        myInvocationHandler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),myInvocationHandler);
    }
}

测试:ApiTest

package com.qf.design.create.abstractfactory.design.factory;

import com.qf.design.create.abstractfactory.design.workshop.ICacheAdapter;
import com.qf.design.create.abstractfactory.design.workshop.impl.EGMCacheAdapter;
import com.qf.design.create.abstractfactory.design.workshop.impl.IIRCacheAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ApiTest {
    private static Logger logger= LoggerFactory.getLogger(Logger.class);
    public static void main(String[] args) {
        ICacheAdapter proxyInstance01 = (ICacheAdapter) JDKProxyFactory.getProxyInstance(new IIRCacheAdapter());
        proxyInstance01.set("mykey","values01");
        String mykey01 = proxyInstance01.get("mykey");
        logger.info("IIR values:"+mykey01);

        ICacheAdapter proxyInstance02 = (ICacheAdapter) JDKProxyFactory.getProxyInstance(new EGMCacheAdapter());
        proxyInstance02.set("mykey","values02");
        String mykey02 = proxyInstance02.get("mykey");
        logger.info("EGM values:"+mykey02);
    }
}

UML关系图

未使用抽象工厂模式
每新增一个实现,需要重新进行if else判断,修改之前的代码逻辑
在这里插入图片描述

抽象工厂模式:都共同实现接口ICacheAdapter,以便于jdk动态代理对象获取每个代理对象
在这里插入图片描述
总结:
这个设计模式满⾜了;单⼀职责开闭原则解耦等优点,但如果说随着业务的不断拓展,可能会造成类实现上的复杂度。但也可以说算不上缺点,因为可以随着其他设计⽅式的引⼊和代理类以及⾃动⽣成加载的⽅式降低此项缺点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA【设计模式】抽象工厂模式 的相关文章

  • Antlr 处理异常

    我使用 Antlr 3 和 AST 树开发了一个复杂的语法 ANTLR 生成词法分析器和解析器 问题是 例如 当用户输入无效的语法时 该语法需要 用户没有输入此内容 然后在我的 Eclipse IDE 中出现以下异常 line 1 24 m
  • Selenium webdriver :列表不是通用的;它不能使用参数 `` 类型进行参数化

    我试图将链接存储在列表中 请按照以下代码操作 public class frameswitch public static void main String args System setProperty webdriver gecko d
  • 匿名内部类显示不正确的修饰符

    据我了解 以下代码应该打印true作为输出 但是 当我运行这段代码时 它正在打印false 来自 Java 文档15 9 5 匿名类 https docs oracle com javase specs jls se8 html jls 1
  • 无法从 TemporalAccessor 获取 OffsetDateTime

    当我这样做时 String datum 20130419233512 DateTimeFormatter formatter DateTimeFormatter ofPattern yyyyMMddHHmmss withZone ZoneI
  • Selenium - 保存网站,包括所有图像、css、dom

    我想使用 firefox 或 chrome 访问带有 selenium 的页面 当页面加载时 我想从页面下载所有图像 css dom 我想存储每张图像 就像我在其中找到它们一样 chrome gt Tools gt Development
  • @NotNull.List 的目的

    当我查看标准时限制条件 http docs oracle com javaee 6 api javax validation constraints package summary html在 Bean Validation API JSR
  • 可以混合使用 JVM 语言吗?即:Groovy 和 Clojure

    我知道你可以轻松地混合groovy java clojure java 无论什么JvmLang java 这是否也意味着我也可以让 clojure 和 groovy 代码进行交互 如果我使用 Grails 或 jRoR 我也可以在该环境中使
  • 从 org.w3c.dom.Node 获取 Xpath

    我可以从 org w3c dom Node 获取完整的 xpath 吗 假设当前节点指向 xml 文档中间的某个位置 我想提取该元素的 xpath 我正在寻找的输出 xpath 是 parent child1 chiild2 child3
  • Java 泛型和数字类型

    我想创建一个通用方法来有效地执行此操作 class MyClass static
  • 如何连接hibernate和DB2

    我正在运行一个使用 struts 和 hibernate 的应用程序 我目前正在使用 Derby 数据库 现在我必须转向 DB2 数据库 请告诉我 我必须做什么配置 休眠配置文件 我必须设置任何类路径吗 多变的 我知道 DB2 有两个 ja
  • 在 javafx 中注册鼠标处理程序,但处理程序不是内联的

    我有一个 JavaFX 应用程序变得有点大 我想保持代码的可读性 我有一个折线图 我希望内置缩放功能 该功能在单击鼠标时发生 我知道我需要向图表注册鼠标侦听器 我无法从 Oracle 示例中弄清楚什么 即如下所示 http docs ora
  • Spring @Value 添加验证小于

    我使用以下属性值注入 我如何向此操作添加小于验证 我的意思是我想设置一个验证user maxpassiveday可以说 财产价值不得低于 100 Value user maxpassiveday int maxpassiveday 使用Sp
  • 将传入字符串的 unicode 表示形式转换为 UTF-8?

    我正在读取一些已经转换为 html 样式 代码的数据 我现在需要将其转换回 UTF 8 字符以供查看 不幸的是我无法使用浏览器查看该字符串 我读过有关 java 中的转换的内容 似乎如果你有一个 uxxxx 字符串 那么编译器会为你转换 然
  • 在 Java 中打开现有文件并关闭它。

    是否可以在java中打开一个文件附加数据并关闭多次 例如 psuedocode class variable declaration FileWriter writer1 new FileWriter filename fn1 writer
  • 如何在 Spring Boot 中创建 Apache POI Excel 视图配置

    当我想使用 Spring Boot Web 将数据导出到 Excel 时遇到问题 我使用 Thymeleaf 作为模板引擎 由 Spring Boot 自动配置 但是当我在附加配置中添加 XmlViewResolver 时 由 XmlVie
  • JSP 作为电子邮件模板

    有没有办法发送 MIME 电子邮件 其中电子邮件正文源自 JSP 我需要使用 Javamail 发送一封电子邮件 其中包含一个表格 我认为如果我可以使用 JSP 来完成所有格式设置和布局 将会很方便 在这个线程中 Java 电子邮件模板的建
  • EclipseLink 2.7.0 和 JPA API 2.2.0 - 签名不匹配

    当运行由maven构建的具有以下依赖项的项目时
  • 为什么 HttpServletRequest 输入流为空?

    我有这段代码 我从请求输入流读取输入并使用 JacksonMapper 转换为 POJO 它在具有 guice 支持的 jetty 7 容器中运行 Override protected void doPost HttpServletRequ
  • 如何确保超类的子类方法的线程安全?

    我参加了一次面试 并被要求为以下要求设计一个课程 假设我有一个 A 类 它可以有任意数量的子类 即子类 类 A 有一个名为 doSomething 的方法 该方法是同步的 要求是 A 的所有子类都是强制性的重写 doSomething me
  • RecyclerView 适配器的 Kotlin 泛型

    我正在尝试编写一个通用的 recyclerview 适配器 我找到了几个例子 然而 仍然无法弄清楚如何实现通用适配器 我写的代码是 open abstract class BaseAdapter

随机推荐

  • 比特数据结构课-前言、时间复杂度

    前言 1 什么是数据结构 数据结构 Data Structure 是计算机存储 组织数据的方式 指相互之间存在一种或多种特定关系的数据元素的集合 2 什么是算法 算法 Algorithm 就是定义良好的计算过程 他取一个或一组的值为输入 并
  • 虚拟机出现错误:“无法连接MKS:套接字连接尝试次数太多,正在放弃“,无法进入系统的解决方法

    开发环境 我在windows上使用的是VMware Workstation 14 Pro Ubuntu16 04的组合进行开发 原因 自从将vm从12pro升级成了14pro之后就出现了这种问题 应该是14pro版本本身还有些问题吧 解决方
  • JVM--基础--22--字节码指令

    JVM 基础 22 字节码指令 1 字节码简介 Java字节码由操作码和操作数组成 操作码 1个字节长度 代表某种特定操作含义的数字 操作数 零至多个代表此操作码所需参数 2 字节码与数据类型 在字节码指令集中 大多数指令都有操作所对应的数
  • 力扣412 Fizz Buzz(java+python)

    给你一个整数 n 找出从 1 到 n 各个整数的 Fizz Buzz 表示 并用字符串数组 answer 下标从 1 开始 返回结果 其中 answer i FizzBuzz 如果 i 同时是 3 和 5 的倍数 answer i Fizz
  • Python3,20行代码,通过微信电脑版爬取朋友圈数据,老板再也抓不到我上班看手机了!!!

    爬取微信电脑版朋友圈数据 1 引言 2 桌面图形界面工具介绍 2 1 PyAutoGUI 2 2 PyWinAuto 3 代码实战 1 引言 小屌丝 鱼哥 忙吗 小鱼 忙 小屌丝 想问你件事 小鱼 在忙 没时间 小屌丝 关于妹子的事 小鱼
  • 【Detectron2】入门06:各种模型测试

    FPN voc 训练配置 FPN coco 训练配置 C4 voc 训练配置 Faster RCNN FPN 50 clearn data voc Faster RCNN FPN 50 corrupted data voc Mask RCN
  • github上star较多的三个c++ 内存池memory pool分析

    前言 笔者在写libuv的时候遇到太多uv type t和buffer需要维护了 如果不通过内存池维护 一个是new delete效率非常低 另一个是这种callback和作用域所有权互相耦合的场景 即便是很好的维护了new delete
  • Python处理气象信息grib,grib2文件

    写这篇博客源于博友的提问 1 效果图如下 2 安装 pip install pygrib pip install gributils GRIB 是世界气象组织 World Meterological Organization WMO 用于分
  • windows启动时出现:THE SYSTEM FOUND UNAUTHORIZED CHANGES ON THE FIRMWARE,OPERATIONG SYSTEM OR UEFI DRIVERS

    在启动windows系统容易遇到THE SYSTEM FOUND UNAUTHORIZED CHANGES ON THE FIRMWARE OPERATIONG SYSTEM OR UEFI DRIVERS 尤其是安装完系统以后 尤其针对华
  • MySQL--实战总结

    1 将存在更新部分字段信息 不存在则执行插入合并为一个SQL 需要创建唯一索引 CREATE TABLE user id int 11 NOT NULL AUTO INCREMENT name varchar 255 DEFAULT NUL
  • #CSDN精选博文##学习必备##IT技术学习#系统化学习的第一步:建构自己的知识体系

    大家好 我是小C 全名是CSDN高校俱乐部 我的职责之一是担任 文章过滤器 精选大咖干货 助力学习之路 你是否曾面对海量信息而无从下手 你是否曾苦恼学习效果不佳 事倍功半 你是否曾感叹知识零碎而无法发挥用途 针对这些问题 小C将开启一个全新
  • 数值计算之 最小二乘法(3)最小二乘的矩阵解法

    数值计算之 最小二乘法 3 最小二乘的矩阵解法 前言 回顾最小二乘的线性解 列满秩矩阵的最小二乘解法 Cholesky分解求线性最小二乘解 QR分解求线性最小二乘解 亏秩矩阵的最小二乘解法 SVD分解求亏秩最小二乘解 补充1 超定齐次方程组
  • C++基础STL-deque容器

    双端数组 可以对头端进行插入删除操作 deque 容器和 vecotr 容器有很多相似之处 比如 deque 容器也擅长在序列尾部添加或删除元素 时间复杂度为O 1 而不擅长在序列中间添加或删除元素 deque 容器也可以根据需要修改自身的
  • esxi ssd磁盘IO,IOPS 速度过慢解决方法

    登录SSH 先查看一下加载的驱动 esxcli software vib list grep ahci sata ahci 3 0 26vmw 650 1 26 5969303 VMW VMwareCertified 2020 09 17
  • 全网最全HTML基础

    目录 1 HTML结构 2 HTML 文件基本结构 3 HTML常见标签 3 1注释标签 3 2标题标签 h1 h6 3 3 段落标签 p 3 4 换行标签 br 3 5格式化标签 3 6图片标签 img 3 8表格标签 3 9 合并单元格
  • 禁用 第三方cookie 之后,百度统计会发生什么?

    禁用 第三方cookie 之后 经过亲测 结论是 不一定 百度统计还是有可能知道你是谁的 但可能失准 本想研究一下百度统计是如何统计数据的 发现基本上是利用cookie 大致情况是这样的 名称 用途 有效期 类型 HMACCOUNT Vis
  • Python之sys模块详解

    sys模块 sys 模块提供了许多函数和变量来处理 Python 运行时环境的不同部分 常见用法 sys argv 命令行参数List 第一个元素是程序本身路径 sys modules keys 返回所有已经导入的模块列表 sys exc
  • CAS5.3 服务器集成MySQL8数据库

    MySQL 相关准备 1 安装MySQL8 并安装相关数据库实例 省略一千字 2 新建ucas auth user表 并增加相关用户条记录 DROP TABLE IF EXISTS ucas auth user CREATE TABLE u
  • 解决tomcat安装配置后localhost 打不开

    为了这只丑猫能用的方法都用了 终于出来了 也不知道到底哪些是必须的 建议 1 检查端口8080是否被占用 被占用的话参照下方改端口 2 环境变量肯定是要配置的 3 如果以上不可以 那么什么方法都试试吧 前提 下载安装tomcat9和jdk
  • JAVA【设计模式】抽象工厂模式

    抽象工厂模式 一 定义 二 示例 传统硬编码方式 都在一个类里面实现 多重if else嵌套使用 抽象工厂模式 UML关系图 一 定义 抽象工厂模式 类似于动态代理对象的生成工厂 集中管理各个代理对象 使用代理对象解决实际业务场景 减少代码