从零玩转设计模式之抽象工厂设计模式-chouxiangshejimoshi

title: 从零玩转设计模式之抽象工厂设计模式
date: 2022-12-08 16:05:03.28
updated: 2022-12-11 23:03:16.842
url: http://www.yby6.com/archives/chouxiangshejimoshi
categories: 
- 设计模式
tags: 
- 设计模式

什么是抽象工厂设计模式?

抽象工厂模式是一种软件设计模式,它提供了一种方法来创建相关或依赖对象的家族,而不需要指定它们的具体类,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

需满足条件

  • 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品
  • 系统一次只可能消费其中某一族产品,即同族的产品一起使用。

为了学习的目的我进行图片形式展现,各位同学请手动打出自己的设计模式代码

抽象工厂模式包含以下几个角色:

AbstractFactory:抽象工厂,定义创建一组相关或依赖对象的接口。
ConcreteFactory:具体工厂,实现抽象工厂定义的接口,并创建一组具体产品。
AbstractProduct:抽象产品,定义一类产品的接口。
ConcreteProduct:具体产品,实现抽象产品定义的接口,每一个具体产品都是一个完整的对象。
Client:客户端,使用抽象工厂和抽象产品的接口来创建一组相关或依赖对象。

产品族

所谓产品族,是指位于不同产品等级结构中,功能相关联的产品组成的家族。

image-1670486670108

需求

假设现在引入一种新的产品
按照工厂方法模式的写法,自然就要在具体的苹果工厂类里再增加一个新的方法,返回新的苹果实例
同时也要增加新的苹果这个新的产品
其他水果工厂类是一样的做法
这明显违背了 OCP(开闭) 原则
苹果工厂类既能生成进口苹果也能生产国产苹果,违背了单一职责原则
那么我们需要苹果工厂只能生产国产的水果如果需要生产其他的那么就重新创建一个工厂即可

代码实现

抽象产品接口实现

image-1670489310846

抽象产品实现

image-1670489688789

抽象工厂和具体工厂实现

image-1670488428563

运行

image-1670490109660

UML图解析

image-1670490188460

结构

image-1670490201013

依赖关系

image-1670490470521

角色

抽象工厂(Abstract Factory)
	提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
具体工厂(Concrete Factory)
	主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
抽象产品(Product)
	定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
具体产品(ConcreteProduct)
	实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

抽象工厂模式的优缺点

优点
	分离接口和实现
		客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。
		也就是说,客户端从具体的产品实现中解耦
	使切换产品族变得容易
		因一个具体的工厂实现代表的是一个产品族,切换产品族只需要切换一下具体工厂
缺点
	不太容易扩展新的产品,
	如需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂(增加新的接口方法)
	这样就会导致修改所有的工厂实现类

使用场景

  • 系统独立于产品的创建、组成以及表示。
  • 系统配置成具有多个产品的系列,例如 Microsoft Windows或Apple McIntosh类。
  • 相关产品对象系列是共同使用的,而且必须确保这一点。这是该模式的关键,否则可以使用Factory Method模式。
  • 你希望提供产品的类库,只开放其接口,而不是其实现。

源码分析

JDK Connection源码

image-1670490565274

Connection 是一个经典的抽象工厂,而 Statement、PreparedStatement、CallableStatement 是 Connection 这个抽象工厂中提供的三个抽象产品。

Mybatis SqlSessionFactory源码

总结

  • 不同条件下创建不同实例
  • 产品标准化,生产更高效
  • 目的 -> 封装创建细节
你的压力来源于无法自律,只是假装努力,现状跟不上内心欲望,所以你焦虑又恐慌。——杨不易
本文转载于网络 如有侵权请联系删除

相关文章

  • 【题解】乒乓球(枚举模拟)

    题目背景国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白11分制和21分制对选手的不同影响。在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。题目描述华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在11分制和21分制下,双方的比赛结果(截至记录末尾)。比如现在有这么一份记录,(其中W表示华华获得一分,L表示华华对手获得一分):WWWWWWWWWWWWWWWWWWWWWWLW在11分制下,此时比赛的结果是华华第一局11比0获胜,第二局11比0获胜,正在进行第三局,当前比分1比1。而在21分制下,此时比赛结果是华华第一局21比0获胜,正在进行第二局,比分2比1。如果一局比赛刚开始,则此时比分为0比0。直到分差大于或者等于2,才一局结束。你的程序就是要对于一系列比赛信息的输入(WL形式),输出正确的结果。输入格式每个输入文件包含若干行字符串,字符串有大写的W

  • python基础之语言特点

    博主简介:原互联网大厂tencent员工,网安巨头Venustech员工,阿里云开发社区专家博主,微信公众号java基础笔记优质创作者,csdn优质创作博主,创业者,知识共享者。一、背景  Python是一门易于学习、功能强大的编程语言。它提供了高效的高级数据结构,还能简单有效地面向对象编程。Python优雅的语法和动态类型以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的理想语言。下面我们来介绍一下python的特点。二、优点1、简单易学  Python是一种代表简单主义思想的语言。它采用强制缩进的方式使得代码具有较好的可读性,阅读一个良好的Python程序就像是在读英语文章一样。用Python语言编写程序时无需考虑底层的细节,这使得编程人员能够专注于问题本身,从而找到更好的解决方法。2、免费开源  Python是FLOSS(免费自由、开放源码软件)之一。使用者可以自由地发布这个软件的拷贝,阅读它的源代码,对它做改动,或者把它的一部分用于新的自由软件中。3、类库丰富  Python标准库非常庞大,覆盖了网络、文件、GUI、数据库、文本等各种操作。用Python开发,许多功

  • tp5.1 框架数据库高级查询技巧实例总结

    本文实例讲述了tp5.1框架数据库高级查询技巧。分享给大家供大家参考,具体如下:快捷查询快捷查询方式是一种多字段相同查询条件的简化写法,可以进一步简化查询条件的写法,在多个字段之间用|分割表示OR查询,用&分割表示AND查询,可以实现下面的查询,例如:Db::table('think_user') -where('name|title','like','thinkphp%') -where('create_time&update_time','',0) -find();复制生成的查询SQL是:SELECT*FROM `think_user` WHERE( `name`LIKE'thinkphp%'OR`title`LIKE'thinkphp%') AND( `create_time`0AND`update_time`0) LIMIT1复制快捷查询支持所有的查询表达式。区间查询区间查询是一种同一字段多个查询条件的简

  • SAS汉字转拼音解决方案

    在数据处理的工作中,可能会碰到要把汉字转换为对应拼音的问题,如将大量的中文姓名或名称转换成对应的拼音。之前写过一个简单的SAS程序来实现此目的,其主要步骤为:首先要用到汉字拼音对照表,然后将汉字设为宏变量,解析的值为其对应的拼音,接着将处理变量中的每个汉字前插入一个宏解析符号“&”,最后用RESOLVE函数在DATA步执行时解析得到对应的拼音,代码(SAS9.2forWindows)如下:/*导入汉字拼音对照表*/ procimportdatafile="D:\Demo\GB2312汉字拼音对照表(6727字).txt" out=Hanzi_Pinyin(rename=(VAR1=HANZIVAR2=PINYIN)) dbms=dlm replace; guessingrows=1419; delimiter=''; getnames=no; run; /*创建汉字宏变量*/ data_null_; setHanzi_Pinyin; callsymputx(HANZI,PINYIN); run; /*汉字列表*/ procsqlnop

  • 新手ztree结合springmvc 入门生成动态树

    这个是异步加载数据先看效果图这里先看数据库直接上代码<%@pagelanguage="java"contentType="text/html;charset=utf-8" pageEncoding="utf-8"%> <% Stringpath=request.getContextPath(); StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <basehref="<

  • Maven Profile

    MavenProfile什么是MavenProfile在我们平常的java开发中,会经常使用到很多配制文件(xxx.properties,xxx.xml),而当我们在本地开发(dev),测试环境测试(test),线上生产使用(product)时,需要不停的去修改这些配制文件,次数一多,相当麻烦。现在,利用maven的filter和profile功能,我们可实现在编译阶段简单的指定一个参数就能切换配制,提高效率,还不容易出错.profile可以让我们定义一系列的配置信息,然后指定其激活条件。这样我们就可以定义多个profile,然后每个profile对应不同的激活条件和配置信息,从而达到不同环境使用不同配置信息的效果。 MavenProfile入门修改pinyougou-page-web的pom.xml<properties> <port>9105</port> </properties> <build> <plugins> <plugin> <groupId>org.apache

  • Redis实现分布式锁(集群版)

    单机版获取锁:setfile:9527${random_value}NXEX${timeout}释放锁,调用lua脚本:1ifredis.call("get",KEYS[1])==ARGV[1]then 2returnredis.call("del",KEYS[1]) 3else 4return0 5end复制这种实现方式有3大要点(也是面试概率非常高的地方)`set`命令要用`setkeyvaluepxmillisecondsnx`;`value`要具有唯一性;释放锁时要验证`value`值,不能误解锁;事实上这类琐最大的缺点就是它加锁时只作用在一个Redis节点上,即使Redis通过sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况:在Redis的master节点上拿到了锁;但是这个加锁的key还没有同步到slave节点;master故障,发生故障转移,slave节点升级为master节点;导致锁丢失。正因为如此,Redis作者antirez基于分布式环境下提出了一种更高级的分布式锁的实现

  • 【Nature社论】人工智能威胁论绝非耸人听闻

    【新智元导读】Nature日前发表社论,认为人工智能威胁论并非无稽之谈。社论指出,人工智能的发展有可能威胁隐私权和异议权,过于依赖人工智能将产生网络安全隐患,目前无人机等自主进攻武器尚存伦理问题,最重要的是机械取代人之后生产力提高的收益不一定能全社会共享,因此可能导致不平等现象加深。社论最后强调,技术发展应当与科学研究同步,这样技术才不会走偏道路。原文标题:Anticipatingartificialintelligence原文来源:Nature532,413(28April2016)doi:10.1038/532413a2016年1月,美国华盛顿特区的信息技术与创新基金会将年度“卢德奖”(LudditeAward,译注:也被称为阻碍科技进步奖)授予了“2015年因警告世人人工智能或将毁灭人类而搞得公众惶惶不安的一群科学家和知名人士”。获奖者——如果可以这么说的话——包括创业家伊隆·马斯克和物理学家史蒂芬·霍金。2015年1月,马斯克和霍金都签署了一份公开信,主张研究、监管和道德框架确保人工智能对人类有益,并且保证“我们的人工智能系统必须做我们想让它们做的事情”。这哪谈得上“惶惶不安”

  • 腾讯云内容分发网络CDNCC统计数据查询api接口

    1.接口描述接口请求域名:cdn.tencentcloudapi.com。 CC统计数据查询 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:DescribeCcData。 Version 是 String 公共参数,本接口取值:2018-06-06。 Region 否 String 公共参数,本接口不需要传递此参数。 StartTime 是 String 查询起始时间,如:2018-09-0410:40:00,返回结果大于等于指定时间 EndTime 是 String 查询结束时间,如:2018-09-0410:40:00,返回结果小于等于指定时间 Interval 否 String 时间粒度,支持以下几种模式:min:

  • 腾讯云TAPD敏捷项目管理产品优势

    敏捷研发一站式服务提供需求管理、缺陷管理、工时管理、测试管理、发布管理等在内的敏捷产品研发全生命周期解决方案。 快速灵活,随需而变独立封装的应用模块,支持根据研发模式按需组装。搭配工作流引擎、统计报表、项目报告、定时报告等功能,支持团队在不同成长阶段的灵活配置,满足团队的差异化需要。 开放集成,全面接口多样的第三方集成方案,支持企业微信集成、Github&Gitlab代码集成、CI&CD持续发布集成等。丰富的API接口,支持基于TAPD进行个性化开发,打造多样化研发协作平台。 第三方服务集成 企业微信:TAPD与企业微信关联,支持任务管理、消息提醒,扫码登录,协作与沟通更加高效。 代码管理:集成腾讯工蜂TGit、Github、Gitlab第三方代码托管服务,支持代码提交关联,提交趋势统计,软件开发管理一目了然。 持续集成:集成Jenkins、GitlabCI、Ansible主流的CI&CD工具,提供可视化流水线管理,提升产品交付效率。 代码检查/制品管理:集成SonarQube、Nexus主流代码检查于制品管理工具,帮助团队提升代码质量、管理构建产物。 自动化测

  • 01 基于umi搭建React快速开发框架

    介绍 基于umi搭建一个快速开发框架,react应用框架。umi以路由为基础的,支持类next.js的约定式路由,以及各种进阶的路由功能,并以此进行功能扩展,比如支持路由级的按需加载。 我们会在基于umi的基础上,开发出一个框架通用功能和业务功能 框架功能列表 全局layout 权限管理 封装列表增删改查 国际化 集成g2chart图表 集成socket.io ....(后续补充) 业务功能 用户管理 ....(后续补充) 创建项目 umi提供了脚手架供我们快速创建项目。参考umi脚手架创建项目 包管理器我们推荐用yarn来替换npm,yarn在包安装速度上确实提升不少 1.在你的空目录下执行, yarncreateumi 我们需要选择antd,codesplitting,dll,hardsource 复制 2.安装依赖 yarn 复制 3.启动本地开发 yarnstart 复制 构建全局layout和菜单 umi规定src/layouts目录下存放我们全局layout组件,在index.js中加入代码如下 classBaseLayoutextendsReact.Compon

  • vue-实现全选单选

    在获取列表页面数据时,通过forEach遍历存储数据的对象,给对象中添加一个selected变量,值为布尔值。 点击全选时,通过遍历将对象中selected的布尔值改变 点击单选时,被点中的通过筛选加入到新数组中,通过对比新数组和老数组控制全选是否被选中  

  • docker学习路线

    docker学习路线 参考资料 知乎docker的学习路线 Docker—从入门到实践 Docker核心技术与实现原理 Docker入门 《KubernetesinAction》,想要学习Kubernetes的读者一定不要错过。 编程能力影响最大的两本书就是: 《计算机程序的构造和解释》(StructureandInterpertationofComputerProgramming,SICP) 《计算机程序的概念、技术和模型》(Concepts,Techniques,andModelsofComputerProgramming,CTMCP) 理解docker的核心技术(coretech) docker的核心技术有namespace,controlgroups,unionfilesystem Namespaces 命名空间(namespaces)是Linux为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。 Docker其实就通过Linux的Namespaces对不同的容器实现了隔离。 Linux的命名空间机制提供了以下七种不同的命名空间,包括&nb

  • 记录下WIN下配置LINUX虚拟机及PYTHON环境

    因为听说服务器端大多都是LINUX/UNIX,LINUX是程序员必须适应的编程环境,所以今天折腾了一下,给笔记本装了个LINUX虚拟机,并顺便给WINDOWS和LINUX都配置了PYTHON环境。 这里把参考的文和注意事项记录一下备查。 1)WIN下配置LINUX虚拟机 参考LINUX.中国新手指南:手把手安装Ubuntu文章,安装成功。 配置:windows8.1+VirtualBox+Ubuntu 注意事项: 如果用Virtualbox安装Ubuntu,发现无法选择64位系统,那么可能是BIOS的CPU虚拟设置没有开,或者被其他程序(如微软的hyper-v)占用了 我这里是BIOS没有开,开机时按F2或者F10进入BIOS设置界面,找virtualizzationtechnology相关字眼,并修改即可 如果CPU比较老可能不支持这项业务,按cpu型号搜索一下即知。 CPU虚拟好了以后就继续按教程安装下去 这几天试用下来,速度还是很快的,你键盘打字基本不会有延时,双系统办公还是比较合适。 2)Python Linux一般自带PYTHON2和PYTHON3,如上面装的Ubun

  • 将kafka消息解析拷贝

    找到消息日志保存目录 可以看到以.log结尾的消息文件,接下来使用命令解析此文件 执行命令:strings-eS"00000000000000080560.log"|iconv-c-f"UTF-8"-t"UTF-8">xx.txt 可以看到多了一个xx.txt文件,执行命令sz xx.txt,选择保存路径,将文件保存本地电脑即可对消息文件分析。  

  • vmware-workstation-11中centos-6.6安装

    排版比较乱,参见 https://www.zybuluo.com/Jpz/note/144303 VMwareWorkstation11中CentOS6.6安装 Linux开发环境配置 目录   VMware Workstation11中CentOS6.6安装 目录 Linux发行版选择 CentOS安装 Vmware Tools安装 结束语 如果人生的途程上没有障碍,人还有什么可做的呢。——俾斯麦 最近计划把开发环境从windows上迁移到Linux上,希望在平时做开发的时候也能够熟悉linux环境,这个过程将会遇到很多问题,包括Linux发行版选择与安装、开发环境配置和windows常用工具的代替等等,这些问题都必须得到解决并记下来。 Linux发行版选择 Linux发行版数量很多,可以在distrowatch.com上看到他们的排名,Debian、Ubuntu、Fedora、CentOS是我安装过的Linux的发行版,点击量第一的Mint我没有使用过,据说使用起来很方便,和XP很像,适用于家庭用户和企业办公。 想在这么多版本中选择一个是很难的,

  • 二叉树之查找指定节点所在的层数

    在二叉树中实现查找,若查找的元素在二叉树中存在,则得出该元素所在的层数,若不存在,则得出0。例如:在链式存储实现的二叉树中(如下图所示),查找元素。   1.若查找元素“H”,则得出所在层数4;   2.若查找元素“S”,则得出0,表示该元素在树中不存在。   代码如下:   #include<stdio.h> #include<stdlib.h> //树的定义(结点定义) typedefcharDataType; typedefstructNode{ DataTypedata; structNode*lchild; structNode*rchild; }BiNode,*BiTree; //创建树的二叉链表(递归) voidCreateBiTree(BiTree*bt) { charch; ch=getchar(); if(ch==‘.‘)*bt=NULL; else { *bt=(BiNode*)malloc(sizeof(BiNode)); (*bt)->data=ch; CreateBiTree(&

  • 2021年闲扯

    时间越来越长,自己越来越感觉无力。更新博客不勤,体育锻炼基本荒废。越来不喜欢现在的状态,但是感觉有一个无形的东西禁锢着自己,烦。 作者: everfight 出处: http://www.cnblogs.com/everfight/ 欢迎转载

  • 线性表

    集合AUB=A //La表示A集合,Lb表示B集合。 voidunionL(List*La,listLb) { intLa_len,Lb_len,i; ElemTypee; La_len=ListLength(*La); Lb_len=ListLength(Lb); for(i=1;i<=Lb_len;i++) { GetElem(Lb,i,&e); if(!LocateElem(*La,e)) { ListInsert(La,++La_len,e); } } } 复制  线性表的顺序存储结构 结构体定义:#defineMAXSIZE20 typedefintElemType; typedefstruct{ ElemTypedata[MAXSIZE]; intlength; }SqList; 复制 取数操作: ElemTypeGetElem(SqListL,inti,ElemType*e){ if(L.length==0||i<1||i<L.length){ returnERROR; } *e=L.data[i-1];

  • java多线程学习笔记(五)

    补充一个synchronized关键字的结论: 线程A先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法 A线程现持有object对象的Lock锁,B线程如果这个时候调用object对象中的synchronized类型的方法则需要等待,也就是同步 当线程A调用anyObject对象加入synchronized关键字的X方法时,A线程就获得了X方法所在对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,而B线程如果调用声明了synchronize关键字的非X方法时,必须等A线程将X方法执行完,也就是释放对象锁之后才可以调用。这时A已经执行了一个完整的任务,也就是变量已经完成了变化,不存在脏读的基本环境。(X方法和非X方法均处在同一个类下面,是同一个对象的不同方法) 关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,所以在前面例子中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,前提是多个线程访问同

  • noi.ac #534 猫

    题目链接:戳我 【问题描述】 有n座山,m只猫和p个工作人员。山从左往右编号为1∼n,山i和i−1之间的距离是di米。 有一天,猫都到山上去玩了:第i只猫会到山hi去,并一直玩到时间ti,之后就在那座山等待工作人员来接它。 每个工作人员的线路都是从1走到n,并带走沿途任意只在等待的猫。工作人员速度为每单位时间1米,不能在山上停留。 例如,假设有两个山丘,d2=1,有一只猫要到山2去,在t=3结束它的玩耍。如果工作人员在时间2或时间3离开山1,则他可以带走这只猫,但如果在时间1离开山1,他就不能带走它。如果工作人员在时间2离开山1,则猫等待他0个时间单位,如果工作人员在时间3离开山1,则猫等待他1个时间单位。 你的任务是安排每个工作人员从1出发的时间(整数,可以是负数),使所有猫的等待时间总和最小。 【输入格式】 第一行三个整数n,m,p,表示山、猫、工作人员的数目。 第二行n−1个整数表示d2∼dn。 后面m行,每行两个数hi,ti。 【输出格式】 一个整数,表示所有猫的等待时间总和的最小值。 【数据规模】 40%的数据,m≤1000,p≤100。 80%的数据,m≤5000,p≤10

相关推荐

推荐阅读