创建型设计模式02-工厂方法模式

news2025/1/9 16:44:25

✨作者:猫十二懿

❤️‍🔥账号:CSDN 、掘金 、个人博客 、Github

🎉公众号:猫十二懿

工厂方法模式

1、工厂方法模式介绍

工厂方法模式(Factory Method Pattern)是一种常用的对象创建型设计模式,也被称为工厂模式、多态工厂模式和虚拟构造器模式等。该模式通过定义一个抽象工厂接口来创建一系列相关或者相互依赖的对象,而无需指定它们具体的类。

在工厂方法模式中,创建对象的操作延迟到工厂类的子类中去完成,即由子类来决定应该实例化哪一个具体产品类。这样就可以将客户端代码与具体类的实现分离开来,从而降低了客户端与具体类之间的耦合度,同时也有利于系统的扩展和升级。

image-20230418233750530

2、工厂方法模式举例

一个具体的例子是,假设我们正在开发一个电商平台,这个平台中有不同种类的商品需要进行销售。我们可以使用工厂方法模式来创建这些商品的实例。

首先,我们需要定义一个抽象的 Product 接口,这个接口包含了所有商品应该具备的共同属性和行为,比如获取商品名称、获取商品价格等。然后,我们可以针对不同类型的商品,创建具体的产品类,比如 BookProduct、ElectronicProduct 等,这些类都实现了 Product 接口并且具有自己特定的属性和行为。

接下来,我们需要定义一个 ProductFactory 工厂接口,其定义了一个创建产品的通用接口方法 createProduct()。然后针对不同类型的产品,分别创建具体的工厂类,比如 BookProductFactory、ElectronicProductFactory 等,每个工厂类分别实现了创建具体商品实例的方法。比如,BookProductFactory 实现了 createProduct() 方法用于创建具体的书籍商品实例。

  1. Product 接口,包含了所有商品应该具备的共同属性和行为:

    /**
     * @author Shier
     * 产品接口
     */
    public interface Product {
        // 产品共有的名称
        String getName();
    
        // 产品都有价格    
        double getPrice();
        
         // 买的是什么产品
        void productShow();
    }
    
  2. 定义两个具体的产品类 BookProduct 和 ElectronicProduct,实现 Product 接口并且具有自己特定的属性和方法:

    /**
     * @author Shier
     * 书本产品类
     */
    public class BookProduct implements Product {
        private String name;
        private double price;
    
        public BookProduct(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public double getPrice() {
            return this.price;
        }
        
        @Override
        public void productShow() {
            System.out.println("BookProduct{" +
                    "name='" + name + '\'' +
                    ", price=" + price +
                    '}');
        }
    }
    
    /**
     * @author Shier
     *
     * 电子产品类
     */
    public class ElectronicProduct implements Product {
        private String name;
        private double price;
    
        public ElectronicProduct(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public String getName() {
            return this.name;
        }
    
        @Override
        public double getPrice() {
            return this.price;
        }
        
        @Override
        public void productShow() {
            System.out.println("ElectronicProduct{" +
                    "name='" + name + '\'' +
                    ", price=" + price +
                    '}');
        }
    }
    
  3. 定义一个 ProductFactory 工厂接口,其定义了一个创建产品的通用接口方法 createProduct():

    /**
     * @author Shier
     * 产品工厂接口
     */
    public interface ProductFactory {
        Product createProduct();
    }
    
  4. 然后针对不同类型的产品,分别创建具体的工厂类,比如 BookProductFactory、ElectronicProductFactory

    /**
     * @author Shier 
     * 书本工厂
     */
    public class BookProductFactory implements ProductFactory {
        private String name;
        private double price;
    
        public BookProductFactory(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public Product createProduct() {
            return new BookProduct(this.name, this.price);
        }
    }
    
    /**
     * @author Shier 
     * 电子产品工厂
     */
    public class ElectronicProductFactory implements ProductFactory {
        private String name;
        private double price;
    
        public ElectronicProductFactory(String name, double price) {
            this.name = name;
            this.price = price;
        }
    
        @Override
        public Product createProduct() {
            return new ElectronicProduct(this.name, this.price);
        }
    }
    
  5. 在客户端中,我们可以通过调用不同的具体工厂类的 createProduct() 方法,来创建具体类型的商品实例

    public class Client {
        public static void main(String[] args) {
            ProductFactory bookFactory = new BookProductFactory("Java编程思想", 99.9);
            Product book = bookFactory.createProduct();
            book.productShow();
    
            ProductFactory electronicFactory = new ElectronicProductFactory("iPad Pro", 7999);
            Product electronic = electronicFactory.createProduct();
            electronic.productShow();
        }
    }
    

最后输出的结果如下:

image-20230418223313188

这个模式可以将对象的创建和使用分离开来,并且能够提供更高级别的灵活性。当需要创建一组相关的对象时,工厂方法模式通常是非常有用的。例如,一个汽车制造厂可以使用工厂方法来根据不同的需求生产出不同类型的汽车,比如轿车、卡车或者SUV等。

每个具体实现类,都要去新建一个对应工厂类,就是将具体的实现延迟到子类当中进行实现了

4、 实现商场收银系统再次升级

简单工厂+策略+装饰+工厂方法实现

image-20230418233822084

主要的修改如下:

  1. 增加一个接口:

    /**
     * @author Shier
     * CreateTime 2023/4/18 23:02
     */
    public interface IFactory {
        public ISale createSalesModel(); // 共同都有的是销售模式
    }
    
  2. 先打折在满减先满减再打折、创建成一个工厂类,去实现上面这个接口,

    /**
     * @author Shier
     * CreateTime 2023/4/18 23:05
     * 先打折再满减类
     */
    public class CashRebateReturnFactory implements IFactory {
        
        private double moneyRebate = 1d;
        private double moneyCondition = 0d;
        private double moneyReturn = 0d;
    
        public CashRebateReturnFactory(double moneyRebate,double moneyCondition,double moneyReturn){
          this.moneyRebate=moneyRebate;
          this.moneyCondition=moneyCondition;
          this.moneyReturn=moneyReturn;
        }
    
        //先打x折,再满m返n
        public ISale createSalesModel(){
            
            CashNormal cn = new CashNormal();
            CashReturn cr1 = new CashReturn(this.moneyCondition,this.moneyReturn); 
            CashRebate cr2 = new CashRebate(this.moneyRebate);
            
            cr1.decorate(cn);   //用满m返n算法包装基本的原价算法
            cr2.decorate(cr1);  //打x折算法装饰满m返n算法
            return cr2;         //将包装好的算法组合返回
        }    
    }
    
    /**
     * @author Shier
     * CreateTime 2023/4/18 23:05
     * 先满减再打折类
     */
    public class CashReturnRebateFactory implements IFactory {
    
        private double moneyRebate = 1d;
        private double moneyCondition = 0d;
        private double moneyReturn = 0d;
    
        public CashReturnRebateFactory(double moneyRebate, double moneyCondition, double moneyReturn) {
            this.moneyRebate = moneyRebate;
            this.moneyCondition = moneyCondition;
            this.moneyReturn = moneyReturn;
        }
    
        //先满m返n,再打x折
        public ISale createSalesModel() {
    
            CashNormal cn2 = new CashNormal();
            CashRebate cr3 = new CashRebate(this.moneyRebate);
            CashReturn cr4 = new CashReturn(this.moneyCondition, this.moneyReturn);
    
            cr3.decorate(cn2);  //用打x折算法包装基本的原价算法
            cr4.decorate(cr3);  //满m返n算法装饰打x折算法
            return cr4;         //将包装好的算法组合返回
        }
    }
    
  3. 修改CashContext类,直接就使用上面定义好的这两个销售模式类,实现了松耦合的目的

    /**
     * @author Shier
     * CreateTime 2023/4/11 22:55
     */
    public class CashContext {
        /**
         * CashSuper对象
         */
        private ISale cashSuper;
    
        /**
         * 通过构造方法,传入具体的收费策略
         */
        public CashContext(int cashType) {
            //根据用户输入,将对应的策略对象作为参数传入CashContent对象中
            IFactory fs = null;
            switch (cashType) {
                case 1:
                    //原价
                    fs = new CashRebateReturnFactory(1d,0d,0d);
                    break;
                case 2:
                    //打8折
                    fs = new CashRebateReturnFactory(0.8d,0d,0d);
                    break;
                case 3:
                    //打7折
                    fs = new CashRebateReturnFactory(0.7d,0d,0d);
                    break;
                case 4:
                    //满300返100
                    fs = new CashRebateReturnFactory(1,300d,100d);
                    break;
                case 5:
                    //先打8折,再满300返100
                    fs = new CashRebateReturnFactory(0.8d,300d,100d);
                    break;
                case 6:
                    //先满200返50,再打7折
                    fs = new CashReturnRebateFactory(0.7d,200d,50d);
                    break;
                default:
                    break;
            }
            this.cashSuper = fs.createSalesModel();
        }
        /**
         * 根据不同的收费策略返回不同的结构
         */
        public double getResult(double price, int num) {
            return cashSuper.acceptCash(price, num);
        }
    }
    

最后的输出结果:

image-20230418233722368

从中可以发现,工厂方法模式不但做到了简单工厂违背的开闭原则的缺点,还保持了封装对象过程的优点。

5、总结

工厂方法模式包含四个角色:

  1. 抽象产品:所创建对象的父类或接口
  2. 具体产品:创建目标
  3. 抽象工厂:抽象产品的创建工厂
  4. 具体工厂:用于创建具体产品的工厂

工厂方法模式能够满足多种复杂对象的创建需求,并提供了一种灵活的解决方案,可以更好地符合设计原则中的开放封闭原则

优点:

  1. 增强了代码的可扩展性
  2. 降低了耦合度,解耦能力好
  3. 提高了代码的重复使用率
  4. 动态地创建对象
  5. 对于复制的参数的构造对象,可以很好对外层屏蔽代码的复杂性

缺点

  1. 会导致系统中类的个数增加、增加复杂度
  2. 使用时需要先创建工厂对象
  3. 带来额外的开销
  4. 增加了系统的抽象性和理解难度。

应用场景:

  1. 创建对象需要大量重复的代码
  2. 客户端(应用层)不依赖产品类实例如何被创建、如何被实现等细节
  3. 一个类通过其子类来指定创建哪个对象

工厂方法就是简单工厂模式的一个升级版本

的创建工厂
4. 具体工厂:用于创建具体产品的工厂

工厂方法模式能够满足多种复杂对象的创建需求,并提供了一种灵活的解决方案,可以更好地符合设计原则中的开放封闭原则

优点:

  1. 增强了代码的可扩展性
  2. 降低了耦合度,解耦能力好
  3. 提高了代码的重复使用率
  4. 动态地创建对象
  5. 对于复制的参数的构造对象,可以很好对外层屏蔽代码的复杂性

缺点

  1. 会导致系统中类的个数增加、增加复杂度
  2. 使用时需要先创建工厂对象
  3. 带来额外的开销
  4. 增加了系统的抽象性和理解难度。

应用场景:

  1. 创建对象需要大量重复的代码
  2. 客户端(应用层)不依赖产品类实例如何被创建、如何被实现等细节
  3. 一个类通过其子类来指定创建哪个对象

工厂方法就是简单工厂模式的一个升级版本

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

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

相关文章

MAC中文版 FCPX V10.6.6 专属视频剪辑后期工具安装教程

Final Cut Pro X简介 Final Cut Pro X又名FCPX,是MAC上非常不错的视频非线性剪辑软件,它剪辑速度超凡,具有先进的调色功能、HDR 视频支持,以及 ProRes RAW,让剪辑、音轨、图形特效、整片输出,支持主流的摄像机格式,是专业视频剪辑领域的王者…

Java经典笔试题—day14

Java经典笔试题—day14 🔎选择题🔎编程题🍭计算日期到天数转换🍭幸运的袋子 🔎结尾 🔎选择题 (1)定义学生、教师和课程的关系模式 S (S#,Sn,Sd,Dc,SA )(其属性分别为学号、姓名、所…

【数据湖仓架构】数据湖和仓库:范式简介

是时候将数据分析迁移到云端了——您选择数据仓库还是数据湖解决方案?了解这两种方法的优缺点。 数据分析平台正在转向云环境,例如亚马逊网络服务、微软 Azure 和谷歌云。云环境提供了多种好处,例如可扩展性、可用性和可靠性。此外&#xff0…

SpringMVC bean加载控制 -- SpringMVC入门保姆级教程(二)

文章目录 前言二、SpringMVC bean 加载控制1.bean加载控制2.添加Spring开发环境3.SpringMVC bean加载控制4.SpringMVC bean控制相关知识点 总结 前言 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能…

丝印设计~丝印内容、大小、距离、排列,位置

丝印设计 丝印的内容包括: a) PCB的名称/PCB的版本号 b) 元器件外形框 c) 元器件的序号 d) 元器件的极性和方向标志 e) 条码框 f) 插入PCB的名称(母板) g) 插针的位置序号 h) 安装孔位置代号 i) 元器件第1脚的位置代号 j) 过板方向 k) 光纤盘…

分治入门+例题

目录 🥇2.3.2 合并排序 🥇2.3.3 快速排序 🌼P1010 [NOIP1998 普及组] 幂次方 🌳总结 形象点,分治正如“凡治众如治寡,分数是也”,管理少数几个人,即可统领全军 本质&#xff…

js数据类型和六种运算结果为false的情况

数据类型 number:数字(整数、小数、NaN(Not a Number)) string:字符串、单双引皆可 boolean:布尔。true、false null:对象为空 undefined:当声明的变量初始化时,该变量的默认值…

vuex五大核心、辅助函数

一、vuex五大核心 分别为:state、getters、mutations、actions、modules state:用来存放我们的状态,也可以理解数据,类似与data中定义的数据;mutations:可以获取state里面的状态,进行修改,他只…

Hadoop---10、生产调优手册

1、HDFS—核心参数 1.1 NameNode 内存生产配置 1、NameNode内存计算 每个文件块大概占用150byte,一台服务器128G内存为例,能储存多少文件块呢? 12810241024*1024/150Byte ≈ 9.1 亿 G M KB Byte 2、Hadoop2.x系列,配置 NameNode…

leetcode506.相对名次

题目描述跳转leetcode详情 给你一个长度为 n 的整数数组 score ,其中 score[i] 是第 i 位运动员在比赛中的得分。所有得分都 互不相同 。 运动员将根据得分 决定名次 ,其中名次第 1 的运动员得分最高,名次第 2 的运动员得分第 2 高&#xff0…

day1 -- 资料库管理系统DBMS

学习目标: 了解什么是Mysql 如何安装Mysql 学习内容: 资料库概念资料库管理系统概念资料库管理系统分类SQL是什么安装Mysql启动Mysql并建立一张测试表格 正文部分 资料库 比如你喜欢摘抄优美的词句,那些优美的词句就是一种文字资料&#xf…

香橙派4和树莓派4B构建K8S集群实践之六:App服务部署

目录 1. 说明 1.1 关于PHPNginx体系的WebApp,这里将实践两种部署模式: 1.2 配置清单 2. PHPNginx体系的WebApp部署 2.1 单节点多容器模式A 2.1.1 准备工作 2.2.2 部署 2.2.3 访问效果 ​编辑 2.2 多节点单容器模式B 2.2.1 准备工作 2.2 配置…

笔记 | FastAPI创建新项目

当使用FastAPI创建项目时,首先需要安装FastAPI和其依赖项。可以使用pip来安装它们。请确保已经安装了Python和pip。 创建项目文件夹并进入该文件夹: mkdir myproject cd myproject创建并激活一个新的Python虚拟环境(可选,但强烈…

虚拟机扩容

文章目录 虚拟机扩容扩容背景软件版本操作步骤1、VM上修改磁盘信息2、在系统中挂载磁盘(1) 使用命令查看磁盘状态(2) 通过命令查看到新磁盘的分区(3) 然后对新加的磁盘进行分区操作(4)重启虚拟机(5) 再次用以下命令查看到磁盘当前情况(6) 查看卷组名(7) 初始化刚刚的分区(8) 将…

MongoDB入门

mongodb与sql术语对应关系 SQL术语/概念MongoDB术语/概念解释/说明databasedatabase数据库tablecollection数据库表/集合rowdocument数据记录行/文档columnfield数据字段/域indexindex索引 对应关系图例

Microsoft Edge有哪些你不知道却超级好用的插件?(Microsoft Edge功能测评)

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯C语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:对Edge浏览器的简单测评,分享一些自己在使用好用的插件. 目录…

阿里系文生图(PAI+通义)

PAI-Diffusion模型来了!阿里云机器学习团队带您徜徉中文艺术海洋 - 知乎作者:汪诚愚、段忠杰、朱祥茹、黄俊导读近年来,随着海量多模态数据在互联网的爆炸性增长和训练深度学习大模型的算力大幅提升,AI生成内容(AI Gen…

Ae 效果详解:3D 摄像机跟踪器

Ae菜单:效果/透视/3D 摄像机跟踪器 Effects/Perspective/3D Camera Tracker 使用 3D 摄像机跟踪器 3D Camera Tracker效果可自动分析视频,以便提取摄像机运动和 3D 场景数据。然后,可以在 2D 素材的基础上正确合成 3D 元素。 提示&#xff1a…

基于DataX的海量时序数据迁移实战:从MySQL到TDengine3.x

背景 MySQL 数据库中,设备历史数据单表过亿,如何快速、低成本地迁移到 TDengine3.x 中? 从标题可以看出,我们使用的数据迁移/同步工具是 DataX ,数据源( Source )为传统的关系型数据库 MySQL …

Yarn学习笔记

Apache Hadoop YARN (Yet AnotherResource Negotiator,另一种资源协调者)是一种新的 Hadoop 资源管理器,它是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率、资源统一…