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

文章目录

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

概念

抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
工厂方法是有一个类型的产品,也就是只有一个产品的抽象类或接口,而抽象工厂相对于工厂方法来说,是有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();}
}

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

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

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

相关文章

Android Studio实现解析HTML获取图片URL,将URL存到list,进行列表展示

目录 效果build.gradle(app)添加的依赖(用不上的可以不加)AndroidManifest.xml错误代码activity_main.xmlitem_image.xmlMainActivityImage适配器ImageModel 接收图片URL效果 build.gradle(app)添加的依赖(用不上的可以不加) dependencies {implementation com.square…

Python可视化在量化交易中的应用(11)_Seaborn折线图

举个栗子&#xff0c;用seaborn绘制折线图。 Seaborn中折线图的绘制方法 在seaborn中&#xff0c;我们一般使用sns作为seaborn模块的别名&#xff0c;因此&#xff0c;在下文中&#xff0c;均以sns指代seaborn模块。 seaborn中绘制折线图使用的是sns.lineplot()函数&#xff…

springboot+grpc+k8s+istio环境

2023年8月17日&#xff0c;本人之前使用过nacosdubbospringboot、eurekafeign等环境。最近学习到了istio服务网格集成到k8s也可以实现分布式微服务。 1. 环境 Kubernetes集群istio集成到k8sjdk17 (8也ok)gPRC服务间通信 2. 微服务 cloud-config服务是spring-cloud-config-s…

中国剩余定理及扩展

目录 中国剩余定理解释 中国剩余定理扩展——求解模数不互质情况下的线性方程组&#xff1a; 代码实现&#xff1a; 互质&#xff1a; 非互质&#xff1a; 中国剩余定理解释 在《孙子算经》中有这样一个问题&#xff1a;“今有物不知其数&#xff0c;三三数之剩二&#x…

【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…

leetcode做题笔记88. 合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff1a;最终&#xff0c;合并后数组…

Mybatis的SqlSource SqlNode BoundSql

学习链接 MyBatis SqlSource解析 【Mybatis】Mybatis源码之SqlSource#getBoundSql获取预编译SQL Mybatis中SqlSource解析流程详解 Mybatis TypeHandler解析 图解 Mybatis的SqlSource&SqlNode - processon DynamicSqlSource public class DynamicSqlSource implement…

notepad++ verilog关键字自动补全

新建verilog.xml放在安装目录下 D:\Program Files (x86)\Notepad\autoCompletion <?xml version"1.0" encoding"Windows-1252" ?> <NotepadPlus><AutoComplete><KeyWord name"accept_on" /><KeyWord name"a…

mysql自定义实体类框架

根据表结构自动生产实体类和方法,根据反射与io生成,可自定义扩展方法 package com.digital.web.front; /*** pom依赖* <dependency>* <groupId>mysql</groupId>* <artifactId>mysql-connector-java</artifactId>* <version>5.1.27</ve…

设计模式详解-责任链模式

类型&#xff1a;行为型模式 实现原理&#xff1a;为请求创建了一个接收者对象的链。对请求的发送者和接收者进行解耦&#xff0c;每个接收者都包含对另一个接收者的引用&#xff0c;如果一个对象不能处理该请求&#xff0c;那么它会把相同的请求传给下一个接收者&#xff0c;…

极致鸿蒙2.0——华为MatePad系列安装AidLux,一个自带vscode的Python编译环境

看着刚刚人入手的华为鸿蒙系统MatePad11平板&#xff0c;是如此的美轮美奂&#xff0c;但是总感觉少了点什么&#xff0c;少了点什么呢&#xff1f;是编程环境&#xff0c;我爱MatePad&#xff0c;也爱编程&#xff0c;那如果可以在MatePad上编程&#xff0c;会发生什么&#x…

SpringBoot、Java 使用 Jsoup 解析 HTML 页面

使用 Jsoup 解析 HTML 页面 什么是 Jsoup&#xff1f; Jsoup 是一个用于处理 HTML 页面的 Java 库&#xff0c;它提供了简单的 API&#xff0c;使得从 HTML 中提取数据变得非常容易。无论是获取特定标签的内容还是遍历整个页面的元素&#xff0c;Jsoup 都能轻松胜任。 如何使…

【ARM Linux 系统稳定性分析入门及渐进12 -- GDB内存查看命令 “x“(examine)】

文章目录 gdb 内存查看命令 examine 上篇文章&#xff1a;ARM Linux 系统稳定性分析入门及渐进11 – GDB( print 和 p 的使用| 和 &#xff1a;&#xff1a;的使用|ptype|{&#xff1c;type&#xff1e;} &#xff1c;addr&#xff1e; ) gdb 内存查看命令 examine examine是…

c语言——判断,判断是否是字母

//判断&#xff0c;判断是否是字母 #include<stdio.h> #include<stdlib.h> int main() {char c;printf("输入字符&#xff1a;");scanf("%c",&c);if((c>a&&c<z)||(c>A&&c<Z)) //a~z的ASCLL区间是97-122&…

【每日一题Day299】LC2235两整数相加

两整数相加【LC2235】 给你两个整数 num1 和 num2&#xff0c;返回这两个整数的和。 实现 class Solution {public int sum(int num1, int num2) {return num1 num2;} }复杂度 时间复杂度&#xff1a; O ( 1 ) \mathcal{O}(1) O(1)空间复杂度&#xff1a; O ( 1 ) \mathcal{O}…

Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)

文章目录 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)前情提要客户端部分 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三) 前情提要 单例泛型类 using System.Collections; using System.Collections.Generic; …

【C# 基础精讲】自定义异常类

自定义异常类是C#中异常处理的一种重要方式&#xff0c;它允许您创建具有自定义错误信息和处理逻辑的异常类型&#xff0c;以提高程序的可读性和可维护性。通过自定义异常类&#xff0c;您可以为特定的业务逻辑或应用场景创建更有意义的异常&#xff0c;使错误处理更加精确和有…

【Go 基础篇】Go语言关键字和预定义标识符解析:探索编程的基石与核心要素

介绍 在计算机编程中&#xff0c;关键字&#xff08;Keywords&#xff09;和预定义标识符&#xff08;Predefined Identifiers&#xff09;是编程语言的核心要素&#xff0c;它们在语法结构和语言功能中起到重要作用。在Go语言&#xff08;Golang&#xff09;中&#xff0c;关…

虚拟拍摄,如何用stable diffusion制作自己的形象照?

最近收到了某活动的嘉宾邀请&#xff0c;我将分享&#xff1a; 主题&#xff1a;生成式人工智能的创新实践 简要描述&#xff1a;从品牌营销、智能体、数字内容创作、下一代社区范式等方面&#xff0c;分享LLM与图像等生成式模型的落地应用与实践经验。 领域/研究方向&#xff…

1.flink快速入门

前言 下图表示的是一个简单的flink-job的计算图&#xff0c;这种图被称为DAG(有向无环图)&#xff0c;表示的这个任务的计算逻辑&#xff0c;无论是spark、hive、还是flink都会把用户的计算逻辑转换为这样的DAG&#xff0c;数据的计算按照DAG触发&#xff0c;理论上只要构建出…