当前位置: 首页 > news >正文

设计模式篇---抽象工厂(包含优化)

文章目录

    • 概念
    • 结构
    • 实例
    • 优化

概念

抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
工厂方法是有一个类型的产品,也就是只有一个产品的抽象类或接口,而抽象工厂相对于工厂方法来说,是有n个类型的产品,也就具有n个产品的抽象类或接口。通俗的来讲,就是由生成一个类型的产品转变为生成一组产品,这是二者的主要区别,两个的相同点是抽象的工厂接口里关联的永远是抽象的产品。

结构

抽象工厂的类图如下:
在这里插入图片描述
AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品(抽象的产品)。
ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品。
AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。

实例

现在有海尔和海信两家公司,都会生产电视和空调,根据这种场景,我们可以拆分一下,把电视和空调作为产品族,海尔和海信两家公司作为两个生产产品的抽象工厂,它们都可以生产电视和空调。

空调的抽象产品:

public interface HVAC {void displayHVAC();
}

海尔空调:

public class HaierHVAC implements HVAC {@Overridepublic void displayHVAC() {System.out.println("海尔空调");}
}

海信空调:

public class HisenseHAVC implements HVAC{@Overridepublic void displayHVAC() {System.out.println("海信空调");}
}

电视的抽象产品:

public interface TV {void displayTV();
}

海尔电视:

public class HaierTV implements TV{@Overridepublic void displayTV() {System.out.println("海尔电视");}
}

海信电视:

public class HisenseHAVC implements HVAC{@Overridepublic void displayHVAC() {System.out.println("海信空调");}
}

抽象的工厂,海信工厂和海尔工厂实现该接口:

public interface AbstractFactory {TV createTV();HVAC createHVAC();
}

海尔工厂:

public class HaierFactory implements AbstractFactory{@Overridepublic TV createTV() {return new HaierTV();}@Overridepublic HVAC createHVAC() {return new HaierHVAC();}
}

海信工厂:

public class HisenseFactory implements AbstractFactory {@Overridepublic TV createTV() {return new HisenseTV();}@Overridepublic HVAC createHVAC() {return new HisenseHAVC();}
}

客户端实现:

public class Client {public static void main(String[] args) {//创建海尔的空调和电视AbstractFactory haierFactory = new HaierFactory();TV haierTV = haierFactory.createTV();HVAC haierHVAC = haierFactory.createHVAC();haierTV.displayTV();haierHVAC.displayHVAC();}
}

结果:
在这里插入图片描述

优化

抽象工厂比工厂方法多了一个产品族的抽象,也就是可以在工厂里创建多个产品。当新的公司介入时,如长虹公司也来了,那就在实现一个长虹公司的工厂,实现抽象工厂,然后重写里面的方法即可。
但是假如海尔和海信不仅仅生产空调和电视了,还想生产冰箱,那就需要再增加一个产品,这时,海尔和海信工厂都需要增加一个生产冰箱的方法,假如有n个像海尔和海信这样的工厂,那每个工厂都需要重写方法,很难扩展。

于是我苦思冥想,终于想到了一个方案,先说下思路:
1、因为当扩展新的产品时,就要重写工厂的方法,所以这个工厂里,我打算只放一个获取产品的方法,返回类型是一个抽象的产品。
2、要实现完全的开闭原则不太现实,只能减少对原有类的影响,要改的话只改动一个类就好,所以可以把需要变动的地方都放到一个类中,需要变动的点就是扩展新的产品。
3、因为客户面向的是抽象,所以在客户端不能出现具体的产品,只能出现抽象产品,但是可以通过字符串的形式进行传参,这样与每个类都没有耦合。
4、因为海尔和海信的工厂是固定的,可以在里面出现魔法值。

下面是优化的效果:
抽象工厂类,只有一个抽象的方法:

public interface AbstractFactory {Product create(String type);
}

海尔工厂类,可通过反射获取具体的产品:

public class HaierFactory implements AbstractFactory {@Overridepublic Product create(String type) {Map<String, String> productClassNameByType = ExtendUtil.getProductClassNameByType(type);String className = productClassNameByType.get("haier");Object o = null;try {o = Class.forName(className).newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return (Product) o;}
}

海信工厂类:

public class HisenseFactory implements AbstractFactory {@Overridepublic Product create(String type) {Map<String, String> productClassNameByType = ExtendUtil.getProductClassNameByType(type);String className = productClassNameByType.get("hisense");Object o = null;try {o = Class.forName(className).newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return (Product) o;}
}

一个工具类,用来扩展使用,存放产品族和具体产品之间的关系:

public class ExtendUtil {private static Map<String, Map<String, String>> map = new HashMap<>();static {map = new HashMap<String, Map<String, String>>() {{Map<String, String> tvMap = new HashMap<>();tvMap.put("haier", "com.tfjybj.ming.design.absfactory.HaierTV");tvMap.put("hisense", "com.tfjybj.ming.design.absfactory.HisenseTV");put("tv", tvMap);Map<String, String> hvacMap = new HashMap<>();hvacMap.put("haier", "com.tfjybj.ming.design.absfactory.HaierHVAC");hvacMap.put("hisense", "com.tfjybj.ming.design.absfactory.HisenseHVAC");put("hvac", hvacMap);}};}public static Map<String,String>  getProductClassNameByType(String type){return map.get(type);}
}

最抽象的产品:

public interface Product {void display();
}

海尔电视:

public class HaierTV implements Product {@Overridepublic void display() {System.out.println("海尔电视");}
}

海尔空调:

public class HaierHVAC implements Product {@Overridepublic void display() {System.out.println("海尔空调");}
}

海信电视:

public class HisenseTV implements  Product {@Overridepublic void display() {System.out.println("海信电视");}
}

海信空调:

public class HisenseHAVC implements Product{@Overridepublic void display() {System.out.println("海信空调");}
}

客户端使用:

public class Client {public static void main(String[] args) {//创建海尔的空调和电视AbstractFactory haierFactory = new HaierFactory();//客户端面向的是抽象Product tv = haierFactory.create("tv");Product hvac = haierFactory.create("hvac");tv.display();hvac.display();}
}

如果增加新的产品如冰箱,或者新增工厂如长虹电器,则需要改动的地方只有这里:
在这里插入图片描述
欢迎您的观看,有问题一起探讨。

相关文章:

设计模式篇---抽象工厂(包含优化)

文章目录 概念结构实例优化 概念 抽象工厂&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 工厂方法是有一个类型的产品&#xff0c;也就是只有一个产品的抽象类或接口&#xff0c;而抽象工厂相对于工厂方法来说&#xff0c;是有…...

Azure创建可用性集

什么是可用性集 在Azure中&#xff0c;可用性集&#xff08;Availability Set&#xff09;是一种用于提高虚拟机&#xff08;VM&#xff09;可用性和可靠性的功能。它通过将虚拟机分布在不同的物理硬件和故障域中来提供高可用性。每个故障域都是一个独立的电力和网络故障区域&…...

SpringBoot中优雅的实现隐私数据脱敏(提供Gitee源码)

前言&#xff1a;在实际项目开发中&#xff0c;可能会对一些用户的隐私信息进行脱敏操作&#xff0c;传统的方式很多都是用replace方法进行手动替换&#xff0c;这样会由很多冗余的代码并且后续也不好维护&#xff0c;本期就讲解一下如何在SpringBoot中优雅的通过序列化的方式去…...

Elasticsearch集群shard过多后导致的性能问题分析

1.问题现象 上午上班以后发现ES日志集群状态不正确&#xff0c;集群频繁地重新发起选主操作。对外不能正常提供数据查询服务&#xff0c;相关日志数据入库也产生较大延时 2.问题原因 相关日志 查看ES集群日志如下&#xff1a; 00:00:51开始集群各个节点与当时的master节点…...

Unity框架学习--5 事件中心管理器

作用&#xff1a;访问其它脚本时&#xff0c;不直接访问&#xff0c;而是通过发送一条“命令”&#xff0c;让监听了这条“命令”的脚本自动执行对应的逻辑。 原理&#xff1a; 1、让脚本向事件中心添加事件&#xff0c;监听对应的“命令”。 2、发送“命令”&#xff0c;事件…...

(二)结构型模式:3、过滤器模式(Filter、Criteria Pattern)(C++示例)

目录 1、过滤器模式&#xff08;Filter、Criteria Pattern&#xff09;含义 2、过滤器模式应用场景 3、过滤器模式主要几个关键角色 4、C实现过滤器模式的示例 1、过滤器模式&#xff08;Filter、Criteria Pattern&#xff09;含义 &#xff08;1&#xff09;过滤器模式是…...

谷歌在Chrome浏览器中推进抗量子加密技术

近日&#xff0c;Chromium博客上发表的一篇博文称&#xff0c;为了加强网络安全&#xff0c;应对迫在眉睫的量子计算机威胁&#xff0c;谷歌各个团队密切合作&#xff0c;为网络向抗量子密码学的过渡做好准备。 谷歌的Chrome团队在博客中写道&#xff0c;该项目涉及修订技术标准…...

Kotlin的数组

在 Kotlin 中&#xff0c;数组是一种固定大小的有序集合&#xff0c;可以存储相同类型的元素。Kotlin 提供了两种类型的数组&#xff1a;原生数组和数组类。以下是 Kotlin 中数组的详细使用方法&#xff1a; 1.创建数组 Kotlin 支持使用 arrayOf() 函数来创建数组&#xff1a;…...

centos 安装docker

1.更新你的系统: sudo yum update -y2.安装必需的软件包: Docker 需要 yum-utils, device-mapper-persistent-data 和 lvm2 软件包来运行。安装它们&#xff1a; sudo yum install -y yum-utils device-mapper-persistent-data lvm23.设置 Docker 的仓库: 使用以下命令添加 D…...

Oracle-如何判断字符串包含中文字符串(汉字),删除中文内容及保留中文内容

今天遇见一个问题需要将字段中包含中文字符串的筛选出来 --建表 CREATE TABLE HADOOP1.AAA ( ID VARCHAR2(255) ); --添加字段INSERT INTO HADOOP1.AAA(ID)VALUES(理解);....--查询表内容SELECT * FROM HADOOP1.AAA;在网上查找了一下有以下三种方式&#xff1a; 第一种&#…...

File 类的用法, InputStream和Reader, OutputStream和Writer 的用法

前言 普通的文件长这样&#xff1a; 其实目录也是一种特殊文件&#xff1a; 一、文件前缀知识 &#xff08;一&#xff09;绝对路径和相对路径 以盘符开头的的路径&#xff0c;叫做绝对路径&#xff0c;如&#xff1a;D:\360Downloads\cat.jpg 以.或..开头的路径&#xff0c…...

AtCoder Beginner Contest 315 Task:A/B/C/E

A - tcdr 处理字符串简单题&#xff0c;题目要求去除字符串中的a,e,i,o,u即可 #include<iostream> using namespace std; int main() {string s;cin>>s;for(int i0;i<s.length();i){if(s[i]a||s[i]e||s[i]i||s[i]o||s[i]u)continue;cout<<s[i];} }B - T…...

【项目实践】基于LSTM的一维数据扩展与预测

基于LSTM的一维数据拟合扩展 一、引(fei)言(hua) 我在做Sri Lanka生态系统服务价值计算时&#xff0c;中间遇到了一点小问题。从世界粮农组织(FAO)上获得Sri Lanka主要农作物产量和价格数据时&#xff0c;其中的主要作物Sorghum仅有2001-2006年的数据&#xff0c;而Millet只有…...

webshell实践,在nginx上实现负载均衡

1、配置多台虚拟机&#xff0c;用作服务器 在不同的虚拟机上安装httpd服务 我采用了三台虚拟机进行服务器设置&#xff1a;192.168.240.11、192.168.240.12、192.168.240.13 [rootnode0-8 /]# yum install httpd -y #使用yum安装httpd服务#开启httpd服务 [rootnode0-8 /]# …...

LVS+Keepalived集群

keepalived Keepalived及其工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案&#xff0c;可以解决静态路由出现的单点故障问题 在一个LVS服务集群中通常有主服务器&#xff08;MASTER&#xff09;和备份服务器&#xff08;BACKUP&#xff09;两种角色的服务…...

Java的网络编程

网络编程 两台设备之间通过网络实现数据传输&#xff0c;将数据通过网络从一台设备传输到另一台设备 网络 两台或多台设备通过一定物理设备连接起来构成了网络 网络又分为: 局域网:覆盖范围最小&#xff0c;仅仅覆盖一个教室或一个机房城域网:覆盖范围较大&#xff0c;可以…...

kafka配置远程连接

要想实现在本地连接服务器的kafka&#xff0c;则必须在远程kafka配置远程连接 默认的 kafka 配置是无法远程访问的&#xff0c;解决该问题有几个方案。 方案1 advertised.listenersPLAINTEXT://IP:9092 注意必须是 ip&#xff0c;不能是 hostname 方案2 advertised.listene…...

css实现渐变色border

方式1 div {border: 4px solid;border-image: linear-gradient(to right, #8f41e9, #578aef) 1; }/* 或者 */ div {border: 4px solid;border-image-source: linear-gradient(to right, #8f41e9, #578aef);border-image-slice: 1; }作者&#xff1a;MudOnTire 链接&#xff1a…...

管理 IBM Spectrum LSF

管理 IBM Spectrum LSF 了解如何管理 IBM Spectrum LSF 集群&#xff0c;控制守护程序&#xff0c;更改集群配置以及使用主机和队列。 管理 LSF 作业和作业调度策略。 查看作业信息和控制作业。 了解如何配置资源并将其分配给 LSF 作业。 了解如何在 LSF 集群中提交&#xff0…...

117页数字化转型与产业互联网发展趋势及机会分析报告PPT

导读&#xff1a;原文《》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 喜欢文章&#xff0c;您可以点赞评论转发本文&#xff0c;了解更多内容请私信&#xff1a;方…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础

第三周 Day 3 &#x1f3af; 今日目标 理解类&#xff08;class&#xff09;和对象&#xff08;object&#xff09;的关系学会定义类的属性、方法和构造函数&#xff08;init&#xff09;掌握对象的创建与使用初识封装、继承和多态的基本概念&#xff08;预告&#xff09; &a…...