【设计模式】工厂方法模式详解

news/2024/4/29 7:23:59/文章来源:https://blog.csdn.net/weixin_43876121/article/details/136966810

在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目目的;所以说,工厂模式最大的优点就是解耦。

简单工厂(不属于GOF23种设计模式之一):

不是一种设计模式,更像是一种编码习惯

要学习工厂方法,必须先了解什么是简单工厂

结构
  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品:实现或者继承抽象产品的子类(即产品本身)。
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来进行产品的创建
优点

封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。

缺点

增加新产品时还是需要修改工厂类的代码,违背了“开闭原则"

// 定义一个接口或抽象类
interface Shape {void draw();
}// 定义具体的产品类
class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a circle...");}
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a rectangle...");}
}// 定义简单工厂类
class ShapeFactory {// 工厂方法,根据输入参数决定创建哪种产品public static Shape getShape(String type) {if ("circle".equalsIgnoreCase(type)) {return new Circle();} else if ("rectangle".equalsIgnoreCase(type)) {return new Rectangle();} else {throw new IllegalArgumentException("Invalid shape type: " + type);}}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用简单工厂创建不同形状的对象Shape circle = ShapeFactory.getShape("circle");circle.draw();  // 输出: Drawing a circle...Shape rectangle = ShapeFactory.getShape("rectangle");rectangle.draw();  // 输出: Drawing a rectangle...// 尝试创建无效类型try {Shape invalidShape = ShapeFactory.getShape("triangle");} catch (IllegalArgumentException e) {System.out.println(e.getMessage());}}
}

在这个例子中,ShapeFactory是简单工厂,它负责根据传入的字符串类型创建相应的形状对象。客户端代码只需调用工厂方法,不需要关心具体的创建过程。

工厂方法

针对上例中的缺点,使用工厂方法模式就可以完美的解决完全遵循开闭原则。

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。

结构
  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂(Concreteractory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct实现了抽象产品角色所定义的接口,由县体工厂来创建,它同县体工厂之间一一对应

将简单工厂模式升级为工厂方法模式,我们需要将创建具体产品的逻辑移到每个具体工厂类中,而不是集中在一个静态工厂方法中。以下是将简单工厂模式转换为工厂方法模式的Java代码示例:

// 定义一个接口或抽象类
interface Shape {void draw();
}// 定义具体的产品类
class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a circle...");}
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a rectangle...");}
}// 定义抽象工厂类
abstract class ShapeFactory {// 抽象工厂方法,由子类实现以创建具体产品public abstract Shape getShape();
}// 定义具体工厂类
class CircleFactory extends ShapeFactory {@Overridepublic Shape getShape() {return new Circle();}
}class RectangleFactory extends ShapeFactory {@Overridepublic Shape getShape() {return new Rectangle();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用工厂方法模式创建不同形状的对象ShapeFactory circleFactory = new CircleFactory();Shape circle = circleFactory.getShape();circle.draw();  // 输出: Drawing a circle...ShapeFactory rectangleFactory = new RectangleFactory();Shape rectangle = rectangleFactory.getShape();rectangle.draw();  // 输出: Drawing a rectangle...// 如果需要添加更多形状,只需要创建更多的具体工厂类即可,这里不再演示创建三角形的工厂类}
}

在这个工厂方法模式的示例中,我们创建了一个抽象工厂类ShapeFactory,并在其中定义了抽象方法getShape()。然后,我们分别为每种形状创建了具体工厂类(如CircleFactory和RectangleFactory),并在这些类中实现创建相应形状对象的逻辑。客户端代码现在可以根据需求实例化不同的具体工厂类来创建所需形状对象。

优点
  1. 用户只需要知道具体工厂的名称就可得到所要的产品无须知道产品的具体创建过程
  2. 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
缺点

每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

典型案例 Collection.iterator
List<String> list = Arrays.asList("a","b","c","d");
Iterator<String> iterator = list.iterator();
// ArrayList部分源码
public interface AbstractList<E> extends AbstractCollection<E> implements List<E>  {// Iteratorspublic Iterator<E> iterator() {return new Itr();}public ListIterator<E> listIterator() {return listIterator(0);}public ListIterator<E> listIterator(final int index) {rangeCheckForAdd(index);return new ListItr(index);}private class Itr implements Iterator<E>{...}private class ListItr extends Itr implements ListIterator<E>{...}}
// Collection 部分源码
public interface Collection<E> extends Iterable<E> {Iterator<E> iterator();
}
// Interator部分源码
public interface Iterator<E> {boolean hasNext();E next();
}

在Collection中定义了Iterator的抽象方法,而ArrayList又继承Collection,并在类中重写了Interator的方法。
也就是说ArrayList类是在工厂类中创建了Iterator 和ListIterator 的产品。即:

  • Collection接口是抽象工厂类,
  • ArrayList是具体的工厂类;
  • Iterator接口是抽象商品类,
  • ArrayList类中的Iter和ListItr是具体的商品类。
    在具体的工厂类中iterator()方法是创建具体的商品类对象。

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

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

相关文章

快速熟悉ElasticSearch的基本概念

1.全文检索 全文检索是通过文本内容进行全面搜索的技术。通过全文检索可以快速地在大量文本数据中查找包含特定关键词或者短语的文档&#xff0c;并且返回相关的搜索结果。 检索和查询的区别 检索没有搜索条件边界&#xff0c;检索的结果取决于相关性&#xff0c;相关性计算…

命令模式(请求与具体实现解耦)

目录 前言 UML plantuml 类图 实战代码 模板 Command Invoker Receiver Client 前言 命令模式解耦了命令请求者&#xff08;Invoker&#xff09;和命令执行者&#xff08;receiver&#xff09;&#xff0c;使得 Invoker 不再直接引用 receiver&#xff0c;而是依赖于…

leetcode 25 K 个一组反转链表

leetcode 25 K 个一组反转链表 原题链接 问题 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保…

搜维尔科技:【应急演练】【工业仿真】救援模拟演练可视化仿真项目实施

安全救援综合演练系统是一套面向公共安全事故、预案管理、应急救援模拟演练的虚拟仿真解决方案&#xff0c;它为警察、消防以及专门的应急救援保障部门提供一个综合的应急救援培训和仿真演练平台。平台主要通过设计不同的事故模型和特定的灾难场景&#xff0c;定制不同的应急救…

Java毕业设计-基于springboot开发的游戏分享网站平台-毕业论文+答辩PPT(附源代码+演示视频)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1、开发说明2、需求分析3、系统功能结构 三、系统实现展示1、系统功能模块2、后台登录2.1管理员功能模块2.2用户功能模块 四、毕设内容和源代码获取总结 Java毕业设计-基于springboot开发的…

neo4j相同查询语句一次查询特慢再次查询比较快。

现象&#xff1a; neo4j相同查询语句一次查询特慢再次查询比较快。 分析&#xff1a; 查询语句 //查询同名方法match(path:Method) where id(path) in [244333030] and NOT path:Constructor//是rpc的方法match(rpc_method:Method)<-[:DECLARES]-(rpc_method_cls:Class) -…

React 应用实现监控可观测性最佳实践

前言 React 是一个用于构建用户界面的 JavaScript 框架。它采用了虚拟 DOM 和 JSX&#xff0c;提供了一种声明式的、组件化的编程模型&#xff0c;以便更高效地构建用户界面。无论是简单还是复杂的界面&#xff0c;React 都可以胜任。 YApi 是使用 React 编写的高效、易用、功…

GK7202V330国科微 GK7202RNCFV330 GOKE

GK7202V330 芯片是国科针对消费类 Camera 市场推出的支持 ISP 和 H.265 编码的新一代消费类 Camera SOC 芯 片。 该芯片集成专用的 ISP&#xff0c;拥有高效的视频编码处理性能&#xff0c;支持 H.265 编码&#xff0c;满足客户各种差异化业务需求。集 成了 RTC、POR、Audio …

【Pt】马灯贴图绘制过程 02-制作锈迹

目录 一、边缘磨损效果 二、刮痕效果 三、边缘磨损与刮痕的混合 四、锈迹效果 本篇效果&#xff1a; 一、边缘磨损效果 将智能材质“Iron Forge Old” 拖入图层 打开“Iron Forge Old” 文件夹&#xff0c;选中“Sharpen”&#xff08;锐化&#xff09;&#xff0c;增大“…

【QT入门】 QListWidget各种常见用法详解之图标模式

往期回顾 【QT入门】 Qt代码创建布局之多重布局变换与布局删除技巧-CSDN博客 【QT入门】 QTabWidget各种常见用法详解-CSDN博客 【QT入门】 QListWidget各种常见用法详解之列表模式-CSDN博客 【QT入门】 QListWidget各种常见用法详解之图标模式 QListWidget有列表和图标两种显…

Python-VBA编程500例-024(入门级)

字符串写入的行数(Line Count For String Writing)在实际应用中有着广泛的应用场景。常见的应用场景有&#xff1a; 1、文本编辑及处理&#xff1a;在编写或编辑文本文件时&#xff0c;如使用文本编辑器或文本处理器&#xff0c;经常需要处理字符串并确定其在文件中的行数。这…

如何在Win10使用IIS服务搭建WebDAV网站并实现无公网IP访问内网文件内容

文章目录 前言1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透&#xff0c;将WebDav服务暴露在公网3.1 安装cpolar内网穿透3.2 配置WebDav公网访问地址 4. 映射本地盘符访问 前言 在Windows上如何搭建WebDav&#xff0c;并且结合cpolar的内网穿透工具实现在公网访…

深入MNN:开源深度学习框架的介绍、安装与编译指南

引言 在人工智能的世界里&#xff0c;深度学习框架的选择对于研究和应用的进展至关重要。MNN&#xff0c;作为一个轻量级、高效率的深度学习框架&#xff0c;近年来受到了众多开发者和研究人员的青睐。它由阿里巴巴集团开源&#xff0c;专为移动端设备设计&#xff0c;支持跨平…

keil调试仿真退出卡死现象解决办法

更新到keil5版本V5.20之后&#xff0c;目前一直到V5.29版本&#xff0c;都存在一个问题&#xff1a; 退出调试模式时&#xff0c;有可能会卡死&#xff01; 此时需要在任务管理器中结束掉进程才能强制关闭keil工程。 网上查找了很多资料&#xff0c;一种是退出仿真时不能有断…

python读取excel,转换成json格式,for国际化前端菜单

# -*- coding: utf-8 -*-import pandas as pd import json# 读取Excel文件中的数据 excel_file rD:\解析excel\中英.xlsx df pd.read_excel(excel_file)# 生成中文JSON和英文JSON cn_data {} en_data {} pu_data {} special_data_cn {} special_data_en {} special_data…

Flink系列之:Flink SQL Gateway

Flink系列之&#xff1a;Flink SQL Gateway 一、Flink SQL Gateway二、部署三、启动SQL Gateway四、运行 SQL 查询五、SQL 网关启动选项六、SQL网关配置七、支持的端点 一、Flink SQL Gateway SQL 网关是一项允许多个客户端从远程并发执行 SQL 的服务。它提供了一种简单的方法…

HarmonyOS实战开发-实现带有卡片的电影应用

介绍 本篇Codelab基于元服务卡片的能力&#xff0c;实现带有卡片的电影应用&#xff0c;介绍卡片的开发过程和生命周期实现。需要完成以下功能&#xff1a; 元服务卡片&#xff0c;用于在桌面上添加2x2或2x4规格元服务卡片。关系型数据库&#xff0c;用于创建、查询、添加、删…

目前常见的搜索引擎有哪些?

常见的搜索引擎可以分为两类&#xff1a;全网搜索类和平台内搜索。 全网搜索类是指可以在互联网范围内进行搜索的引擎&#xff0c;它们提供了广泛的搜索结果&#xff0c;包括网页、图片、视频、新闻等各种类型的内容。以下是一些常见的全网搜索引擎&#xff1a; 百度&#xff…

蓝桥OJ3514 子串简写 (暴力+二分)

子串简写 一.暴力 思路: 只能通过60%。 从字符串开头遍历&#xff0c;如果遇到c1就进入子遍历&#xff0c;遇到长度大于等于k且以c2结尾的子串就使cnt;遍历完之后再从外遍历找c1。 这种方法的弊端在于&#xff1a;外遍历 #include<bits/stdc.h> using namespace std; con…

MongoDB Atlas维护指南:常见类型、注意事项与窗口设置

为了给Atlas用户更好的产品体验&#xff0c;MongoDB产品团队会进行定期维护。 本文将会介绍&#xff1a; 常见维护项目种类及频率&#xff0c;注意事项维护期间的影响及建议维护窗口设置说明维护告警设置和邮件通知范例 维护窗口常见项目 定期SSL证书轮换软件升级&#xff…