设计模式—工厂方法模式

news2024/12/25 2:22:13

工厂方法模式

文章目录

    • 工厂方法模式
      • 工厂方法模式是什么
      • 理解工厂方法模式
      • 代码实例
      • 运行截图
      • 工厂方法的优点
      • 工厂方法的不足


工厂方法模式是什么

  • 工厂方法模式属于创建型模式,也叫抽象构造模式, 工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。在使用时,用于只需知道产品对应的具体工厂,关注具体的创建过程,甚至不需要知道具体产品类的类名,当我们选择哪个具体工厂时,就已经决定了实际创建的产品是哪个了。

理解工厂方法模式

  • 这种模式是在原先的层级上多加了一层 实现的效果就是,不由原先的工厂类来实例对象工厂父类来定义创建产品的公共接口, 而各工厂子类对象通过集成来实现这个创建接口, 在这个实现里面去完成究竟应该实例化哪一个具体产品,这样就可以在不影响原先种类的情况下引入新的产品。

代码实例

  • 在这个代码实例中,我们将模拟订购pizza的场景,这次我们加入风味元素,如有北京风味的芝士披萨、伦敦风味的牛肉披萨等。
  1. 我们先定义各种产品类,他们有一个抽象父类,如Pizza类,具体产品类都继承自他
  2. 然后创建一个抽象工厂类,在这个抽象工厂种定义一个抽象的创建方法,后续让子类去实现
  3. 创建多种具体实现创建接口的实现类,在实现类中来决定具体创建哪一个pizza类
  4. 创建订购类,在这个类中实现各种方法的调用

/**
 * 这种模式是在原先的层级上多加了一层
 * 实现的效果就是,不由原先的工厂类来实例对象
 * 工厂父类来定义创建产品的公共接口,
 * 而各工厂子类对象通过集成来实现这个创建接口,
 * 在这个实现里面去完成究竟应该实例化哪一个具体产品
 * 这样就可以在不影响原先种类的情况下引入新的产品
 */

import java.util.Scanner;

public class 工厂方法 {
    public static void main(String[] args) {
        new Order().buy();
    }
}

//定义一个购买订单
class Order {
    public void buy() {
        Scanner in = new Scanner(System.in);
        while (true) {
            System.out.print("您需要什么地方的pizza:");
            String address = in.nextLine();
            PizzaFactory factory = null;
            if ("bj".equals(address)) {
                factory = new BjPizzaFactory();
            } else if ("ld".equals(address)) {
                factory = new LDPizzaFactory();
            }else {
                System.out.println("没有这个地方的口味哦");
                continue;
            }
            System.out.print("您需要什么口味的pizza:");
            String type = in.nextLine();

            Pizza pizza = factory.createPizza(type);
            System.out.println("订单需要为:" + pizza.pizzaName + "  " + pizza);
            if (pizza != null) {
                pizza.material();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
        }
    }
}

//定义一个pizza创建工厂类
abstract class PizzaFactory {
    abstract public Pizza createPizza(String pizzaType);
}

class BjPizzaFactory extends PizzaFactory {

    @Override
    public Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new BjCheesePizza("芝士");
        } else if (type.equals("beef")) {
            return new BjBeefPizza("牛肉");
        } else {
            System.out.println("没有此类型的pizza");
            return null;
        }
    }
}

class LDPizzaFactory extends PizzaFactory {

    @Override
    public Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new LDCheesePizza("芝士");
        } else if (type.equals("beef")) {
            return new LDBeefPizza("牛肉");
        } else {
            System.out.println("没有此类型的pizza");
            return null;
        }
    }
}

abstract class Pizza {
    String pizzaName;

    Pizza(String pizzaName) {
        this.pizzaName = pizzaName + "披萨";
    }

    //准备材料
    abstract public void material();

    void bake() {
        System.out.println("正在烤 " + this.pizzaName);
    }

    void cut() {
        System.out.println("正在切 " + this.pizzaName);
    }

    void box() {
        System.out.println("正在打包 " + this.pizzaName);
    }
}

//利用多个披萨类来继承
class BjCheesePizza extends Pizza {


    BjCheesePizza(String pizzaName) {
        super(pizzaName);
    }

    @Override
    public void material() {
        System.out.println("正在准备北京芝士披萨的材料");
    }
}

class BjBeefPizza extends Pizza {

    BjBeefPizza(String pizzaName) {
        super(pizzaName);
    }

    @Override
    public void material() {
        System.out.println("正在准备北京牛肉披萨的材料");
    }
}

class LDCheesePizza extends Pizza {

    LDCheesePizza(String pizzaName) {
        super(pizzaName);
    }

    @Override
    public void material() {
        System.out.println("正在准备伦敦芝士披萨的材料");
    }
}

class LDBeefPizza extends Pizza {

    LDBeefPizza(String pizzaName) {
        super(pizzaName);
    }

    @Override
    public void material() {
        System.out.println("正在准备伦敦牛肉披萨的材料");
    }
}

运行截图

在这里插入图片描述
在这里插入图片描述

工厂方法的优点

  1. 不关心创建细节: 用户只需要关心产品所对应的工厂,不需要关心它内部是如何创建
  2. 符合开闭原则: 加入新的产品,只需要增加新的工厂类就可以,符合开闭原则,提高了可扩展性

工厂方法的不足

  1. 增加了代码的复杂性: 因为需要增加具体工厂类,所以类的个数容易过多,增加了系统的复杂度(除了编写新的产品类之外,还要编写该产品类的对应工厂类)。
  2. 增加难度: 增加了系统的抽象性和理解难度(工厂方法本身利用了抽象,该模式中会引入抽象层,如果需要动态创建产品类,还需要引入反射技术)。

设计模式的使用 , 要根据实际的业务场景 , 模型综合平衡考量 , 不能过分遵守设计原则 和 设计模式

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

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

相关文章

高级语言(C语言)、汇编语言、机器语言区别?编译器如何将高级语言编译成机器语言?

⾼级语⾔: 是相对于汇编语⾔⽽⾔的,是⾼度封装了的编程语⾔,与低级语⾔相对。它是以⼈类的⽇常语⾔为基础的⼀种编程语⾔,使⽤⼀般⼈易于接受的⽂字来表⽰(例如汉字、不规则英⽂或其他外语),从…

(二十四)List系列集合

目录 前言: 一、List集合的特有方法 二、List集合的遍历方式有几种? 三、Arraylist集合底层原理 四、LinkedList的特点 前言: List集合包括JavaList接口以及List接口的所有实现类。List集合中的元素允许重复,各元素的顺序放是对象插入的顺序&#xff…

C生万物 | C语言文件操作指南汇总【内附文件外排序源码】

👑作者主页:Fire_Cloud_1 🏠学习社区:烈火神盾 🔗专栏链接:万物之源——C 文章目录一、为什么使用文件?二、什么是文件?1、程序文件2、数据文件3、文件名三、文件的打开和关闭1、文件…

自动化测试【软件测试】

自动化测试 什么是自动化 有效减少人力的消耗,同时提高生活的质量 通过自动化测试有效减少人力的投入,同时提高了测试的质量和效率 由于回归测试,版本越来越多,版本回归的压力越来越大,仅仅通过人工测试来回归所有版本…

2.3、进程控制

整体框架 1、什么是进程控制? 进程控制的主要功能是对系统中的所有进程实施有效的管理, 它具有创建新进程、撤销已有进程、实现进程状态转换等功能。 简单来说:进程控制就是要实现进程状态转换 2、如何实现进程控制? 2.1、进程…

ATAC-seq分析:TSS 信号(7)

ATACseq ATACseq - 使用转座酶并提供一种同时从单个样本的转录因子结合位点和核小体位置提取信号的方法。 1. 数据类型 上面这意味着我们的数据中可能包含多种信号类型。 我们将从无核小体区域和转录因子(我们的较短片段)周围获得信号。我们的一部分信号…

2-Spring核心与设计思想

目录 1.Spring是什么? 2.容器是什么? 3.IoC是什么? 3.1.传统程序开发 3.2.控制反转式程序开发 3.3.对比总结规律 4.理解Spring IoC 4.1.将对象(Bean)存入到容器(Spring); 4.2.从容器中取出对象。 5.DI概念说明 1.Spring…

计算机编程背景

💖 欢迎来阅读子豪的博客(JavaEE篇 🤴) 👉 有宝贵的意见或建议可以在留言区留言 💻 欢迎 素质三连 点赞 关注 收藏 🧑‍🚀码云仓库:补集王子的代码仓库 不要偷走我小火…

classpath类路径是什么

Spring Boot 一、简介 classpath类路径在 Spring Boot 中既指程序在打包前的/java/目录加上/resource目录,也指程序在打包后生成的/classes/目录。两者实际上指的是同一个目录,里面包含的文件内容一模一样。 二、获取classpath路径 以下两种方式均可…

Icarus Verilog

Icarus Verilog 是一个Verilog仿真工具,以编译器的形式工作,将以verilog编写的源代码编译为某种目标格式。如果要进行仿真的话,可以生成一个vvp的中间格式,由其所附带的vvp命令执行。 https://github.com/steveicarus/iverilog …

面试官:请设计一个能支撑百万连接的系统架构!

目录 1、到底什么是连接?2、为什么每次发送请求都要建立连接?3、长连接模式下需要耗费大量资源4、Kafka遇到的问题:应对大量客户端连接5、Kafka的架构实践:Reactor多路复用6、优化后的架构是如何支撑大量连接的 这篇文章&#x…

SQL Server 全文索引的应用

在公司项目中提出了一个需求: 搜索包含指定关键词的数据。得到这需求后,站在技术角度考虑第一时间就联想到使用SQL里面“like”查询语句。进一步分析需求后,发现“Like”查询满足不到实际的要求。 示例: ---------------------…

【Ajax】接口与接口测试工具PostMan

一、接口接口的概念使用 Ajax 请求数据时,被请求的 URL 地址,就叫做数据接口(简称接口)。同时,每个接口必须有请求方式。例如:http://www.liulongbin.top:3006/api/getbooks 获取图书列表的接口(GET请求)ht…

【4 - 降维算法PCA和SVD - 案例部分】菜菜sklearn机器学习

课程地址:《菜菜的机器学习sklearn课堂》_哔哩哔哩_bilibili 第一期:sklearn入门 & 决策树在sklearn中的实现第二期:随机森林在sklearn中的实现第三期:sklearn中的数据预处理和特征工程第四期:sklearn中的降维算法…

为何香港的IB状元特别多?

今年IB预科课程(The International Baccalaureate Diploma Programme,IBDP)公开考试放榜,香港的学校又是大丰收的一年!因为香港今年一共有九十三名IB状元,即IB的总分为四十五分满分,而他们全部取…

Linux 环境部署 Nexus 服务

一 私服是什么? 一个特殊的远程仓库,它是架设在局域网内的仓库服务,供局域网内的开发人员使用。 当Maven需要下载构建的使用, 它先从私服请求,如果私服上没有的话,则从外部的远程仓库下载,然后…

算力服务亟待破局,超聚变向新而行

“超聚变已独立活下来。”超聚变产品线总裁范瑞琦在2023新品发布会上透露。自从一年多前从华为体系独立,超聚变公司的未来就颇受业界关注。一方面,算力产业蒸蒸日上,各方尤为关注超聚变的产业定位以及发展算力产业的着力点;另一方…

mysql存储过程的流程控制

本文来说下mysql存储过程的流程控制语句 文章目录流程控制概述IF语句CASE语句LOOP语句LEAVE语句ITERATE语句REPEAT语句WHILE语句本文小结流程控制概述 存储过程中可以使用流程控制来控制语句的执行。 MySQL中可以使用IF语句、CASE语句、LOOP语句、LEAVE语句、ITERATE语句、REPE…

Cesium设置模型朝向速度矢量方向

Cesium设置模型朝向速度矢量方向 文章目录Cesium设置模型朝向速度矢量方向1. 需求场景2. 技术路线2.1 VelocityOrientationProperty2.2 VelocityVectorProperty3. 参考链接1. 需求场景 现有一段飞机起飞、爬升的轨迹数据,需要在Cesium中模拟出飞行过程动画&#xf…

Lesson 3. 线性回归的手动实现(3.3 线性回归手动实现与模型局限 3.4 机器学习模型结果可信度理论与交叉验证基础)

文章目录一、线性回归手动实现与模型局限1. 线性回归的手动实现2. 线性回归模型局限3. 线性回归的决定系数二、机器学习模型结果可信度理论与交叉验证基础1. 机器学习模型结果可信度理论基础与数据集划分1.1 机器学习模型结果可信度基础理论1.2 数据集切分方法1.3 线性回归手动…