简单工厂模式抽象工厂模式

一.简单工厂模式

1.什么是工厂模式

工厂模式的核心就是把对象的生产过程交给工厂来完成,当外部需要一个对象时,由工厂提供接口来获取对象,这样一来即使生产对象的过程变了,仍然不影响外部对对象的获取和使用。

2.举个栗子

定义Chef(厨师),Coder(程序员)两个类。

/**
 * 厨师实体类
 */
public class Chef {
    /**
     * 提供一个做事情的方法
     */
    public void doSometing(){
        System.out.println("厨师正在烹调食物...");
    }
}
/**
 *  程序员实体类
 */
public class Coder {
    /**
     * 提供一个做事情的方法
     */
    public void doSometing(){
        System.out.println("程序员正在编写程序...");
    }
}

如果我们要在其它地方使用这两个类,一般我们会这样做。

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        // 创建“厨师”对象
        Chef chef = new Chef();
        // 创建“程序员”对象
        Coder coder = new Coder();

        // 分别调用各自的操作方法
        chef.doSometing();
        coder.doSometing();
    }
}

感觉没有什么其它问题!现在新的需求来了。业务线需要在每个创建对象的地方加上日志,并且还要修改Coder的名字为UICoder,我们应该怎么做呢?假如有很多地方使用了上面创建对象的代码,是不是业务代码都要修改一遍?

此时引入我们的“工厂模式”!

2.1.引入“简单工厂模式”重构代码

2.1.1.定义用户接口并提供一个操作方法。

/**
 * 定义一个用户接口
 */
public interface IUser {
    /**
     * 提供一个操作方法
     */
    void doSometing();
}

2.1.2.Chef,Coder实现该接口并重写操作方法

/**
 * 厨师实体类
 */
public class Chef implements IUser {
    /**
     * 提供一个做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("厨师正在烹调食物...");
    }
}
/**
 *  程序员实体类
 */
public class Coder implements IUser {
    /**
     * 提供一个做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("程序员正在编写程序...");
    }
}

2.1.3.定义工厂方法用于创建对象

/**
 * 定义工厂类
 */
public class UserFactory {
    public static IUser createUser(String userType){
        IUser user = null;
        switch (userType){
            case "Chef" :
                user = new Chef();
                break;
            case "Coder" :
                user = new Coder();
                break;
        }
        return user;
    }
}

2.1.4.测试

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        IUser chef = UserFactory.createUser("Chef");
        IUser coder = UserFactory.createUser("Coder");
        chef.doSometing();
        coder.doSometing();
    }
}

可以看到业务调用方不依赖Chef和Coder了,并且没有了具体的对象创建过程,我们只是让工厂返回我们需要的对象,我们去使用就可以了至于对象的创建过程我们并不关心。回到上面的问题以后不管是创建对象前加日志,还是修改对象的名称,调用方的业务代码不需要更改只需要改工厂类相关的代码就可以了。

3.简单工厂模式总结

它把对象的创建过程封装起来,隐藏了对象创建的细节,根据外部传入的参数来决定返回哪一种对象,它的缺点就是如果要增加对象类型,或者修改某一个对象的创建方法时,就必须修改工厂类,这不符合对象编程设计原则之一的“开闭原则”。

开闭原则:对扩展开放,对修改封闭。在实现新的需求的时候,最好能够只是扩展而不去修改已经写好的代码,这样能够把新需求带来的风险降到最低。

二.抽象工厂模式

由上“简单工厂模式”可以看出,“厨师”,“程序员”对象都是在同一个工厂里面去生产。一旦生产“厨师”对象的工厂代码发生变化。就有可能影响到“程序员”对象的生产。因为都是使用的是同一个工厂,可能存在误改的情况。为了解决这个问题我们可以建两个工厂一个负责“厨师”另一个负责“程序员”对象的生产。这样就实现了解耦合。当修改生产“厨师”对象的工厂代码时不会影响到“程序员”工厂代码。因为两者是分开的。

上面的概念其实就是“抽象工厂模式”。抽象工厂把具体工厂需要做的事情定义好,所有具体的工厂都必须要实现抽象工厂里面的方法,这样业务调用方依赖的是抽象工厂而不是具体的工厂,实现了解耦合。

1.举个栗子

将“简单工厂”改造为“抽象工厂”。

/**
 * 工厂总接口,后续工厂实现此接口用于产生不同的对象
 */
public interface IFactory {
    /**
     * 创建对象方法
     */
     IUser createUser();
}
/**
 * 定义厨师工厂,用于产生“厨师”对象
 */
public class ChefFactory implements IFactory{

    @Override
    public IUser createUser() {
        Chef chef = new Chef();
        return chef;
    }
}
/**
 * 定义程序员工厂,用于产生“程序员”对象
 */
public class CoderFactory implements IFactory{

    @Override
    public IUser createUser() {
        Coder coder = new Coder();
        return coder;
    }
}
/**
 * 定义一个用户接口
 */
public interface IUser {
    /**
     * 提供一个行为方法,后续新加的其它用户类型都实现此接口用于表达不同用户做不同事
     */
    void doSometing();
}
/**
 * 厨师实体类
 */
public class Chef implements IUser {
    /**
     * 实现IUser接口中做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("厨师正在烹调食物...");
    }
}
/**
 *  程序员实体类
 */
public class Coder implements IUser {
    /**
     * 实现IUser接口中做事情的方法
     */
    @Override
    public void doSometing(){
        System.out.println("程序员正在编写程序...");
    }
}
/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        // 创建工厂对象
        IFactory chefFactory = new ChefFactory();
        // 通过工厂创建“厨师”对象
        IUser chefUser = chefFactory.createUser();
        // 执行业务方法
        chefUser.doSometing();

        // 创建工厂对象
        CoderFactory coderFactory = new CoderFactory();
        // 通过工厂创建“程序员”对象
        IUser coderUser = coderFactory.createUser();
        // 执行业务方法
        coderUser.doSometing();
    }
}

2.抽象工厂模式总结

业务调用处需要具体的对象时就使用具体工厂类去创建对象,因为不同工厂是分开的当修改某个具体工厂时不会影响到其它工厂。抽象工厂模式的缺点也很明显,当新增一种对象的生产时需要额外增加一个具体的工厂类,如果新增的对象很多那么具体的工厂类就会非常多。其次它把具体的工厂对象创建过程暴露给了业务调用处,不利于解耦合。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

上海计算机学会 2023年10月月赛 乙组T3 树的连通子图(树、树形dp)

第三题:T3树的连通子图 标签:树、树形 d p dp dp题意:给定一棵 n n n个结点的树, 1 1 1号点为这棵树的根。计算这棵树连通子图的个数,答案对 1 , 000 , 000 , 007 1,000,000,007 1,000,000,007取余数。题解&#xff1…

HTML内联框架

前言&#xff1a; 我们有时候打开网页时会有广告窗的出现&#xff0c;而这些窗口并不是来自于本站的&#xff0c;而是来自于外部网页&#xff0c;只是被引用到了自己网页中而已。这一种技术可以通过内联来实现。 标签介绍&#xff1a; HTML 内联框架元素 (<iframe>) 表示…

基于Springboot的影城管理系统

基于SpringbootVue的影城管理系统的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页展示 电影信息 电影资讯 后台登录页 后台首页 用户管理 电影类型管理 放映…

RAG (Retrieval Augmented Generation) 结合 LlamaIndex、Elasticsearch 和 Mistral

作者&#xff1a;Srikanth Manvi 在这篇文章中&#xff0c;我们将讨论如何使用 RAG 技术&#xff08;检索增强生成&#xff09;和 Elasticsearch 作为向量数据库来实现问答体验。我们将使用 LlamaIndex 和本地运行的 Mistral LLM。 在开始之前&#xff0c;我们将先了解一些术…

vue3 生命周期(生命周期钩子 vs 生命周期选项 vs 缓存实例的生命周期)

vue3 支持两种风格书写&#xff1a;选项式 API 和组合式 API 若采用组合式 API &#xff0c;则使用生命周期钩子若采用选项式 API &#xff0c;则使用生命周期选项两者选用一种即可&#xff0c;不建议同时使用&#xff0c;避免逻辑紊乱。 生命周期钩子 在 setup 中使用 onBefo…

Vue 阶段练习:记事本

将 Vue快速入门 和 Vue 指令的学习成果应用到实际场景中&#xff08;如该练习 记事本&#xff09;&#xff0c;我们能够解决实际问题并提升对 Vue 的技能掌握。 目录 功能展示 需求分析 我的代码 案例代码 知识点总结 功能展示 需求分析 列表渲染删除功能添加功能底部统计…

3D目标检测实用技巧(二)- 实现点云(or 体素)向图像平面的投影并可视化

一、引言 受Focals Conv的启发&#xff0c;该论文中通过将点云投影到图片中清晰展现出点云学习后的情况&#xff1a; 本次实现的是体素向图像投影并显示&#xff0c;实现出来的效果如下&#xff1a; 二、 实现细节 1、体素投影到图像坐标系 这里我们参考的是VirConv的投影函…

通过matlab分别对比PSO,反向学习PSO,多策略改进反向学习PSO三种优化算法

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 粒子群优化算法 (PSO) 4.2 反向学习粒子群优化算法 (OPSO) 4.3 多策略改进反向学习粒子群优化算法 (MSO-PSO) 5.完整程序 1.程序功能描述 分别对比PSO,反向学习PSO,多策略改进反向学…

百货商场用户画像描绘与价值分析

目录 内容概述数据说明实现目标技术点主要内容导入模块1.项目背景1.1 项目背景与挖掘目标 2.数据探索与预处理2.1 结合业务对数据进行探索并进行预处理2.2 将会员信息表和销售流水表关联与合并 3 统计分析3.1 分析会员的年龄构成、男女比例等基本信息3.2 分析会员的总订单占比&…

Python 入门指南(四)

原文&#xff1a;zh.annas-archive.org/md5/97bc15629f1b51a0671040c56db61b92 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十章&#xff1a;哈希和符号表 我们之前看过列表&#xff0c;其中项目按顺序存储并通过索引号访问。索引号对计算机来说很有效。它们是整…

使用 Docker 部署 SurveyKing 调查问卷系统

1&#xff09;SurveyKing 介绍 SurveyKing 是一款功能强大、操作简便的开源问卷系统。它不仅满足了用户对问卷调查的基本需求&#xff0c;还提供了丰富的逻辑设置和灵活的问题设置&#xff0c;使得问卷制作更加智能化和个性化。此外&#xff0c;SurveyKing 还具有快速部署和安全…

笔记本电脑上的聊天机器人: 在英特尔 Meteor Lake 上运行 Phi-2

对应于其强大的能力&#xff0c;大语言模型 (LLM) 需要强大的算力支撑&#xff0c;而个人计算机上很难满足这一需求。因此&#xff0c;我们别无选择&#xff0c;只能将它们部署至由本地或云端托管的性能强大的定制 AI 服务器上。 为何需要将 LLM 推理本地化 如果我们可以在典配…

elmentui树形表格使用Sortable拖拽展开行时拖拽bug

1、使用elemntui的el-table使用Sortable进行拖拽&#xff0c;如下 const el this.$el.querySelector(.el-table__body-wrapper tbody) Sortable.create(el, {onEnd: (event) > {const { oldIndex, newIndex } event//拿到更新前后的下标即可完成数据的更新} })2、但是我这…

docker 环境变量设置实现方式

1、前言 docker在当前运用的越来广泛&#xff0c;很多应用或者很多中间软件都有很多docker镜像资源&#xff0c;运行docker run 启动镜像资源即可应用。但是很多应用或者中间件有很多配置参数。这些参数在运用过程怎么设置给docker 容器呢&#xff1f;下面介绍几种方式 2 、do…

Day91:API攻防-接口安全SOAPOpenAPIRESTful分类特征导入项目联动检测

目录 API分类特征-SOAP&OpenAPI&RESTful API分类特征 API常见漏洞 API检测流程 API检测项目-Postman&APIKit&XRAY 工具自动化-SOAP - WSDL Postman 联动burpxray APIKit插件(可联动xray) 工具自动化-OpenApi - Swagger Postman 联动burpxray APIKit…

HarmonyOS开发实例:【分布式邮件】

概述 基于TS扩展的声明式开发范式编程语言编写的一个分布式邮件系统&#xff0c;可以由一台设备拉起另一台设备&#xff0c;每次改动邮件内容&#xff0c;都会同步更新两台设备的信息。效果图如下&#xff1a; 搭建OpenHarmony开发环境 完成本篇Codelab我们首先要完成开发环境…

OpenStack:开源云计算的崛起与发展

目录 一&#xff0c;引言 二&#xff0c;OpenStack的起源 三&#xff0c;OpenStack的版本演进 四&#xff0c;OpenStack跟虚拟化的区别 五&#xff0c;OpenStack组件介绍 1&#xff09;Horizon介绍 2&#xff09;KeyStone介绍 Keystone 功能概览 Keystone 架构详解 3&a…

RabbitMQ 各种通信模式的Python实现

一、RabbitMQ 原理 1、基本原理 RabbitMQ是流行的开源消息队列系统&#xff0c;用erlang语言开发。RabbitMQ是AMQP&#xff08;高级消息队列协议&#xff09;的标准实现。支持多种客户端&#xff0c;如&#xff1a;Python、Java、Javascript、C#、C/C,Go等&#xff0c;支持AJ…

RabbitMQ Stream插件使用详解

2.4版为RabbitMQ流插件引入了对RabbitMQStream插件Java客户端的初始支持。 RabbitStreamTemplateStreamListener容器 将spring rabbit流依赖项添加到项目中&#xff1a; <dependency><groupId>org.springframework.amqp</groupId><artifactId>sprin…

【echarts】使用 ECharts 绘制3D饼图

使用 ECharts 绘制3D饼图 在数据可视化中&#xff0c;饼图是表达数据占比信息的常见方式。ECharts 作为一个强大的数据可视化库&#xff0c;除了标准的二维饼图&#xff0c;也支持更加生动的三维饼图绘制。本文将指导你如何使用 ECharts 来创建一个3D饼图&#xff0c;提升你的…
最新文章