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

news2024/11/16 8:24:34

文章目录

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

概念

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

结构

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

实例

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

空调的抽象产品:

public interface HVAC {
    void displayHVAC();
}

海尔空调:

public class HaierHVAC implements HVAC {

    @Override
    public void displayHVAC() {
        System.out.println("海尔空调");
    }
}

海信空调:

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

电视的抽象产品:

public interface TV {
    void displayTV();
}

海尔电视:

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

海信电视:

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

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

public interface AbstractFactory {

    TV createTV();

    HVAC createHVAC();
}

海尔工厂:

public class HaierFactory implements AbstractFactory{
    @Override
    public TV createTV() {
        return new HaierTV();
    }

    @Override
    public HVAC createHVAC() {
        return new HaierHVAC();
    }
}

海信工厂:

public class HisenseFactory implements AbstractFactory {
    @Override
    public TV createTV() {
        return new HisenseTV();
    }

    @Override
    public 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 {

    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public void display() {
        System.out.println("海尔电视");
    }
}

海尔空调:

public class HaierHVAC implements Product {

    @Override
    public void display() {
        System.out.println("海尔空调");
    }
}

海信电视:

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

海信空调:

public class HisenseHAVC implements Product{

    @Override
    public 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.coloradmin.cn/o/900066.html

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

相关文章

qsort函数详解

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解qsort函数&#xff0c;如果你觉得我写的不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 文章目录 一. qsort函数参数详解1.数组首元素地址base2.数组的元素个数num和元素所占内存空间大小w…

Xxl-job安装部署以及SpringBoot集成Xxl-job使用

1、安装Xxl-job&#xff1a; 可以使用docker拉取镜像部署和源码编译两种方式&#xff0c;这里选择源码编译安装。 代码拉取地址&#xff1a; https://github.com/xuxueli/xxl-job/tree/2.1.2 官方开发文档&#xff1a; https://www.xuxueli.com/xxl-job/#%E3%80%8A%E5%88%…

uni-app的Vue.js实现微信小程序的紧急事件登记页面功能

主要功能实现 完成发生时间选择功能&#xff0c;用户可以通过日期选择器选择事件发生的时间。实现事件类型选择功能&#xff0c;用户可以通过下拉选择框选择事件的类型。添加子养殖场编号输入框&#xff0c;用户可以输入与事件相关的子养殖场编号。完成事件描述输入功能&#…

C++笔记之条件变量(Condition Variable)与cv.wait 和 cv.wait_for的使用

C笔记之条件变量&#xff08;Condition Variable&#xff09;与cv.wait 和 cv.wait_for的使用 参考博客&#xff1a;C笔记之各种sleep方法总结 code review! 文章目录 C笔记之条件变量&#xff08;Condition Variable&#xff09;与cv.wait 和 cv.wait_for的使用1.条件变量&…

msf和cs联动

cs设置外部监听器 在vps上执行 vim /etc/ssh/sshd_config AllowTcpForwarding yes GatewayPorts yes TCPKeepAlive yes PasswordAuthentication yes systemctl restart sshd.service 在kali上执行&#xff0c;进行端口转发 ssh -C -f -N -g -R 0.0.0.0:1234:192.168.1.30:…

STM32开关输入控制220V灯泡亮灭源代码(附带PROTEUSd电路图)

//main.c文件 /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body************************************************************************…

525. 连续数组

525. 连续数组 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 525. 连续数组 https://leetcode.cn/problems/contiguous-array/description/ 完成情况&#xff1a; 解题思路&#xff1a; 参考代码&#xff1a; …

奇舞周刊第503期:图解串一串 webpack 的历史和核心功能

记得点击文章末尾的“ 阅读原文 ”查看哟~ 下面先一起看下本期周刊 摘要 吧~ 奇舞推荐 ■ ■ ■ 图解串一串 webpack 的历史和核心功能 提到打包工具&#xff0c;可能你会首先想到 webpack。那没有 webpack 之前&#xff0c;都是怎么打包的呢&#xff1f;webpack 都有哪些功能&…

喜讯?宁德时代首个零碳工厂成功建立,碳中和“任重道远”

8月19日消息&#xff0c;据宁德时代消息&#xff0c;广东瑞庆时代新能源科技有限公司宣布获得国际认可机构SGS颁发的PAS2060碳中和认证证书&#xff0c;从而正式成为一家零碳工厂。这标志着宁德时代首个储能电池为主的零碳工厂成功建立&#xff0c;也是公司继四川时代宜宾工厂之…

编程练习(3)

一.选择题 第一题&#xff1a; 函数传参的两个变量都是传的地址&#xff0c;而数组名c本身就是地址&#xff0c;int型变量b需要使用&符号&#xff0c;因此答案为A 第二题&#xff1a; 本题考察const修饰指针变量&#xff0c;答案为A,B,C,D 第三题&#xff1a; 注意int 型变…

速通蓝桥杯嵌入式省一教程:(五)用按键和屏幕实现嵌入式交互系统

一个完整的嵌入式系统&#xff0c;包括任务执行部分和人机交互部分。在前四节中&#xff0c;我们已经讲解了LED、LCD和按键&#xff0c;用这三者就能够实现一个人机交互系统&#xff0c;也即搭建整个嵌入式系统的框架。在后续&#xff0c;只要将各个功能加入到这个交互系统中&a…

赏味不足:详细来聊下轻资产运作,我从不做重资产

来源&#xff1a;BV1F84y1g7u3 好 大家好&#xff0c;是这样子的 对吧&#xff0c;因为最近聊了也很多&#xff0c;然后我在过程当中也发现&#xff0c;很多人对于不管是创业还是做副业&#xff0c;还是说找一条多种路&#xff0c;就是说可能不是那么清晰&#xff0c;然后我在这…

使用Dockerfile部署java项目

1、移动java包到创建的目录下 2、编写Dockerfile文件 在同一目录下使用如下命令创建文件 touch Dockerfile 文件内容如下&#xff1a; #依赖的父镜像 FROM java:8 #作者 MAINTAINER maxurui #jar包添加到镜像中 ADD springboot3-0.0.1-SNAPSHOT.jar springboot3-0.0.1-SNAPSHO…

射频同轴线阻抗

射频同轴线阻抗 射频同轴线的阻抗与线的绝缘介质的介电常数有关&#xff0c;与线的屏蔽层半径与内部导线半径的比值有关&#xff1a; R 0 1 2 π μ ′ ϵ ′ ln ⁡ ( r 2 r 1 ) \begin{align} R_0\frac{1}{2\pi}\sqrt{\frac{\mu^{}}{\epsilon^{}}}\ln(\frac{r_2}{r_1}) \en…

图数据库_Neo4j中文版_Centos7.9安装Neo4j社区版3.5.9_基于jdk1.8---Neo4j图数据库工作笔记0012

由于我们在国内使用啊,具体还是要用中文版滴,找了好久这个neo4j,原来还是有中文版的, https://we-yun.com/doc/neo4j-chs/ 中文版下载地址在这里: 所有版本都在这里了,需要哪个自己去下载就可以了,要注意下载以后,参考: https://we-yun.com/blog/prod-56.html 在这个位置下载…

Linux系统--进程间通信

文章目录 什么是进程间通信匿名管道命名管道 system V共享内存 system V消息队列 信号量 一、什么是进程间通信 首先由于进程运行是具有独立性的&#xff0c;具有独立的页表&#xff0c;PCB和虚拟地址空间等&#xff0c;父子进程间数据互补干扰。这就让进程间通信难度加大。由…

C语言:字符函数和字符串函数

往期文章 C语言&#xff1a;初识C语言C语言&#xff1a;分支语句和循环语句C语言&#xff1a;函数C语言&#xff1a;数组C语言&#xff1a;操作符详解C语言&#xff1a;指针详解C语言&#xff1a;结构体C语言&#xff1a;数据的存储 目录 往期文章前言1. 函数介绍1.1 strlen1.…

最新觅知扶风视频解析计费系统源码V1.8.2 免授权优化版 附教程

最新觅知扶风视频解析计费系统源码V1.8.2 免授权优化版 附教程 之前有分享过 1.7.1 的扶风计费系统&#xff0c;那个版本很久了之前也一直没有更新&#xff0c;拿到源码之后进行优化&#xff0c;因历史版本的加载和原版的加载速度真的是慢的感人&#xff0c;因此从零开始进行去…

发布一个开源的新闻api(整理后就开源)

目录 说明: 基础说明 其他说明: 通用接口&#xff1a; 登录: 注册: 更改密码(需要token) 更换头像(需要token) 获取用户列表(需要token): 上传文件(5000端口): 获取文件(5000端口)源码文件&#xff0c;db文件均不能获取: 验证token(需要token): 获取系统时间: 文件…