Head First设计模式(阅读笔记)-04.工厂模式

news2025/7/6 20:41:32

披萨订购

假设要完成披萨订购的功能,披萨的种类很多,比如 GreekPizzCheesePizz 等,披萨店会根据用户需要的披萨种类制作披萨,制作的流程包括prepare->bake->cut->box


简单实现

下面代码的实现十分简单清晰,但是如果披萨类型增加或删除,需要去修改代码,不符合开闭原则(类应该对扩展开发,对修改关闭)


// 下面不同的pizza类型都继承了相同的父类
Pizza orderPizza(String type){
    Pizza pizza;
    if(type.equals("cheese")){
        pizza = new CheesePizza();
    }else if(type.equals("clam")){
        pizza = new ClamPizza();
    }
    
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    
    return pizza;
}

工厂模式


简单的披萨工厂-简单工厂模式

从上述代码可以看出,出了创建披萨对象的代码需要修改,其他代码都是不变的,所以可以将创建披萨对象的代码分离出来作为一个新对象-披萨工厂:

  • 此时orderPizza方法变为该工厂的客户,它无需知道工厂如何得到一个披萨,只关心从工厂可以得到一个披萨,并且可以调用方法对披萨进行准备、烘烤等操作
  • 并且该工厂可以有许多客户,比如制作披萨点的菜单就可以利用该工厂制作的披萨来制定价钱等

// 简单披萨工厂
public class SimplePizzaFactory{
    public Pizza createPizza(String type){
        Pizza pizza = null;
        if(type.equals("cheese")){
            pizza = new CheesePizza();
        }else if(type.equals("clam")){
            pizza = new ClamPizza();
        }
        return pizza;
    }
}
public class PizzaStore{
    SimplePizzaFactory factory;
    // 披萨店需要指定一个工厂
    public PizzaStore(SimplePizzaFactory factory){
        this.factory = factory;
    }
    public Pizza orderPizza(String type){
    	Pizza pizza;
    	factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
}

加盟披萨店-工厂方法模式

此时在纽约等地区想在当地加盟该披萨店,并且希望工厂能加工出纽约风味的披萨


给每个地区创建一个工厂

下面代码的缺陷在于无法让各地区的加盟店决定自己的制作流程,只是决定采用哪个工厂而已

NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("Veggie");  // 在纽约工厂制作的纽约风味披萨
让加盟店自己决定制作流程

原本由一个对象负责所有具体类的实例化,现在通过子类负责实例化


public abstract class PizzaStore{
    // orderPizza可以声明为final,防止被子类覆盖
    public Pizza orderPizza(String type){
        Pizza pizza;
        pizza = createPizza(type)  // 从createPizza方法从工厂中移到披萨店中
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    // 定义为抽象,必须实现
    protected abstract Pizza createPizza(String type);
}

public class NYPizzaStrore extends PizzaStore{
    // 子类全权负责实例化哪个具体Pizza,父类并不知道具体创建的披萨是哪一种,只知道这个披萨要进行烘烤、切片等流程
    Pizza createPizza(String item){
        if(item.equals("chess")){
            return new NYStyleCheesePizza();
        }else if(...){
            ...
        }
    }
}

// 定义一个抽象的披萨类
public abstract class Pizza{
    String name;
    void cut(){
        System.out.println("切成方块");
    }
}

// 纽约风味的披萨
public class NYStyleCheesePizza extends Pizza{
    public NYStyleCheesePizza(){
        name = "NYStyle with cheese"
    }
    void cut(){
        System.out.println("切成三角形");
    }
}

// 测试
public class Test{
    public static void main(String[] agrs){
        PizzaStore nyStore = new NYPizzaStrore();
        Pizza pizza = nyStore.orderPizza("cheese");  // nyStore决定要制作什么披萨
    }
}
工厂方法模式

定义了一个创建对象的接口,由子类决定要实例化哪个类


在这里插入图片描述

依赖倒置原则

对于工厂方法模式还依赖了一个原则-依赖倒置原则,该原则表示要依赖抽象,不要依赖具体类,换个说法就是高层组件和低层组件都应该依赖于抽象


在这里插入图片描述

使用当地原材料-抽象工厂模式

假设不同地区的加盟店制作披萨要求用当地的原材料制作


创建当前原料工厂

很明显可以想到,不可能只存在一家工厂生产不同地区需要的原料,然后空运过去,可以在当地创建一个原料工厂


// 抽象原料工厂
public interface PizzaIngredientFactory{
    public Sauce createSauce();
    public Cheese createCheese();
}
// 纽约的原料工厂
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
    public Sauce createSauce(){
        return new NYSauce();  // 使用当前材料
    }
    ...
}
重新制作披萨

// 抽象披萨类,将prepare方法定义为抽象了
public abstract class Pizza{
    String name;
    Sauce sauce;
    Cheese Cheese;
    // 声明为抽象是因为现在当地披萨需要使用自己的原材料进行准备
    abstract void prepare();
    void cut(){
        System.out.println("切成方块");
    }
}
// 现在根据使用不同的原料工厂就可以区分出是哪个地区的CheesePizza了
public class CheesePizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    // 只需要传入需要地区的原料工厂即可
    public CheesePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory = ingredientFactory;
    }
    void prepare(){
        // 通过传入的原料工厂就可以生产出该工程的sauce
    	sauce = ingredientFactory.createSauce();
		...
    }
}

public class NYPizzaStore extends PizzaStore{
    Pizza createPizza(String item){
        Pizza pizza = null;
        // 纽约加盟店肯定使用纽约原料工厂了
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if(item.equals("chess")){
            // 现在不需要写为NYStyleCheesePizza,只需要传入对于原料工厂即可
            pizza = new CheesePizza(ingredientFactory);
        }else if(...){
            ...
        }
        return pizza;
    }
}

// 测试(代码没有变化)
public class Test{
    public static void main(String[] agrs){
        PizzaStore nyStore = new NYPizzaStrore();
        Pizza pizza = nyStore.orderPizza("cheese");
    }
}
抽象工厂模式

提供一个接口用于创建相关或依赖对象的家族,并且不需要明确具体类(比如在NYPizzaStorecreatePizza方法中,并没有明确具体的NYStyleCheesePizza,而是传入一个原料工厂)


参考

Head First 设计模式-工厂模式

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

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

相关文章

从0到0.1学习 lambda表达式(Java版)

编码几年时间,有一个东西似乎一直也逃不过去,那就是lambda表达式。 无论是c#,Python还是Java,lambda的思想都是共通的。但以下的语法和实例为java。 现在就来说说这个看似很难的lambda表达式 什么是lambda表达式? l…

【owt-server】m88分支和m59-server

OWT 单独有个webrtc的仓库,里面有m88的分支Merged Upgrade sdk to m88 for webrtc node #1026 提交记录 主干merge Merge pull request #1026 from starwarfan/mst-88webrtc-m88 目录 构建修改

【信管2.2】项目管理知识体系与组织结构

项目管理知识体系与组织结构上一次课中,我们已经学过了项目以及项目管理的概念,这些内容帮我们认识到了项目到底是个什么东西,有什么特点,和运营有什么区别等等。今天我们就继续沿着项目这件事说下去,我们将一起探讨一…

【知识网络分析】共引网络(co-citation)

共引网络(co-citation) 1 读取本地文献构建共引网络数据集2 网络数据集精简3 社团群体划分4 节点中心度相关指标计算1 读取本地文献构建共引网络数据集 RC.networkCoCitation()方法中的参数与RC.networkCitation()方法中的参数功能一致。该案例中使用的数据集同样为2020-202…

SpringBoot框架保姆级笔记一看就会

文章目录 文章目录文章目录[toc]1️⃣ 简介一. 什么是 [IoC](https://so.csdn.net/so/search?qIoC&spm1001.2101.3001.7020) 容器?二. AOP面向切面编程三. SSM整合四. HttpServletRequest五. HttpServletResponse六. Cookie 与 Session七. Cookie八. Session九…

Java异常01:Error 和 Exception

什么是异常 # 实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的实际要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据…

最全面的SpringMVC教程(一)——SpringMVC简介

前言 本文为SpringMVC相关教程,下边将对SpringMVC进行简单介绍,具体包含:对MVC架构的回顾,什么是SpringMVC,SpringMVC编程示例(包含配置版示例、注解版示例),初识SpringMVC&#xff…

NM DEV Mathematics for Java 【suanshu.net免费】

NM Dev是一个面向对象、高性能、经过广泛测试和专业记录的数学编程库,在S2上运行。自 2010 年开发以来,它是大量经过编码的数值算法,因此它们是可靠的面向对象、统一和可测试的。编程经验或数学知识很少的用户可以通过快速组合类轻松地为他或…

备战 2023 春招,P7 大咖手打 26 大后端面试专题神技,1500 题解析助力

年过后,不少人已经蓄势待发,信心满满地准备投递简历,到处面试,在不同的 Offer 之中择优而栖。 与此同时,也有人会悔恨自己这半年进步不大,每天噼里啪啦敲代码,但面对那些不能再熟悉的 Java 面试…

大数据毕设选题 - 生成对抗网络的照片上色动态算法设计与实现(深度学习 opencv python)

文章目录1 前言1 课题背景2 GAN(生成对抗网络)2.1 简介2.2 基本原理3 DeOldify 框架4 First Order Motion Model1 前言 🔥 Hi,大家好,这里是丹成学长的毕设系列文章! 🔥 对毕设有任何疑问都可以问学长哦! 这两年开始…

Linux项目后端部署及JDKTomcatMySQL安装

前言 上一篇文章简单的分享了在VMware上安装linux系统,本篇文章将要分享的内容是使用linux系统完成项目的部署 一、前置准备工作 在Windows系统中,我们要在开发环境下才能进行项目的开发。那么在linux系统中也是,在安装完linux系统后&#xf…

NoSuchMethodError的常见原因和通用解决方式

目录 环境信息 问题描述 错误分析 解决方法 常见原因 1.第三方包,作用域不对导致应用没导入该包 2.编译时和运行时使用的版本不一样 3.JDK版本不一样 4.多个同路径、同名的类 1.代码复制场景 2.代码移动场景 排查步骤 附录 Maven仲裁机制: …

为啥这么人选择iPhone

01.听音乐(10元/月) 歌曲很全 多个终端支持 果子自带的Music app 在那个设备都可以使用, 包括MacBook Pro,iPhone,iPad,iwatch等 02.周边配件方便购买 03.遇到问题好解决 04.使用稳定,不会有广告&#x…

MySQL海量数据优化(理论+实战) 吊打面试官

一、准备表数据 咱们建一张用户表,表中的字段有用户ID、用户名、地址、记录创建时间,如图所示 ​OK,接下来准备写一个存储过程插入一百万条数据 CREATE TABLE t_user (id int NOT NULL,user_name varchar(32) CHARACTER SET utf8 COLLATE ut…

[附源码]Python计算机毕业设计防疫物资捐赠系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,我…

Vue组件化编程开发

目录 一.模块 二.组件 &#xff08;快捷键< 回车 生成单组件模板&#xff09; 三.非单文件组件 四.单文件组件: 首先理解模块和组件的基本概念: 一.模块 1.理解:向外提供特定功能的js程序&#xff0c;一般就是一个js文件 2.为什么: js文件很多很复杂 3.作用:复用js, 简…

Mybatis-Plus+SpringBoot结合运用

目录 前言 一、创建Maven项目导入相关的依赖 二、在resources添加日志和连接数据库 1.日志文件(log4j.properties) 2.连接数据库&#xff08;application.properties&#xff09; 三、编写pojo &#xff08;注解编写get/set/tostring&#xff09; 四、UserMapper编写继承…

Fragment的生命周期

文章目录Fragment的生命周期Fragment的状态和回调运行状态暂停状态停止状态销毁状态回调方法附加的回调方法onAttach()onCreateView()onActivityCreated()onDestroyView()onDetach()Fragment完整的生命周期图Fragment的生命周期 和Activity一样,Fragment也有自己的生命周期,并…

c++实现图书管理系统v1.0

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录系统要求功能1.首页2.退出系统3.添加图书4.删除书籍5.查找书籍6.修改书籍信息7.显示所有图书8.查看书籍是否在书架上总代码收获系统要求 用c实现一个可以增删改查的…

商城项目环境准备 — docker安装kinaba和配置ik中文分词器

一、拉取kinaba镜像 docker pull kinaba:7.12.1二、启动kinaba容器 docker run -d \ --name kibana \ -e ELASTICSEARCH_HOSTShttp://es:9200 \ --networkes-net \ -p 5601:5601 \ kibana:7.12.1三、访问 输入http://ip:5601 ip&#xff1a;服务器端口 四、安装ik分词器 …