《HeadFirst设计模式》(4)——工厂模式

2023-11-21 20:30

本文主要是介绍《HeadFirst设计模式》(4)——工厂模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 简单工厂模式
  • 工厂方法模式
    • 模式定义
    • 设计原则
    • 问题场景
    • 类图
    • 代码
  • 抽象工厂模式
    • 问题场景
    • 模式定义
    • 类图
    • 代码
  • 工厂方法模式v.s. 抽象工厂模式

前言

当我们使用new实例化具体类时,针对的是实现编程,而不是接口,这会让代码缺乏弹性。比如`

Pizza chickenPizza = new chickenPizza();

虽然左边使用了接口,但右面还是得建立具体类的实例。当有一群具体类并且需要运行时才确定需要实例化哪一个时,通常会写出如下代码:

		Pizza Pizza;if (customer want chickenPizza){pizza = new ChickenPizza();}else if (customer want cheesePizza){pizza = new CheesePizza();} else if (customer want clamPizza) {pizza = new ClamPizza();}

一旦有变化或者扩展,必须要打开这段代码进行修改,比如需要加入新的产品或者一部分产品不需要了。所以,按照封装变化的原则,我们应该把实例化具体类的这部分代码封装起来。

简单工厂模式

简单工厂其实并不能算是一种模式,更像是一种编程习惯。将创建实例的任务放到简单工厂对象中。

public class PizzaStore {SimplePizzaFactory simplePizzaFactory;public PizzaStore(SimplePizzaFactory simplePizzaFactory) {this.simplePizzaFactory = simplePizzaFactory;}public Pizza orderPizza(String type) {//将实例pizza的代码放到简单工厂中Pizza pizza = simplePizzaFactory.createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}
}
public class SimplePizzaFactory {public Pizza createPizza(String type) {switch (type) {case "cheese":return new cheesePizza();case "Bacon":return new baconPizza();default:return null;}}
}

看起来似乎只是将修改换了个地方,而不是不需要修改。其实一个简单工厂通常并不是只有一个客户,而且我们应该将具体实例化过程从客户中移除。(更符合单一职责原则)
常见的使用方式是将简单工厂中创建对象的方法声明为静态方法,这样就不用实例化简单工厂对象,但不能通过继承改变创建方法。

工厂方法模式

模式定义

工厂方法模式 定义了一个创建对象的接口,但由子类决定实例化的类是哪一个。工厂方法把实例化推迟到子类。
所谓的“让子类决定实例化的类”并不是指允许子类在运行时做决定,而是指抽象工厂不知道实际创建的产品是什么。选择了使用哪个子类,自然就决定了实际创建的产品是什么。

设计原则

依赖倒置原则。 要依赖抽象,不要依赖具体类。
在这里插入图片描述
避免违反依赖倒置原则的几个指导方针:

  • 变量不可以持有具体类的引用。如果使用new,就含有了具体类的引用,试试工厂方法。
  • 不要让类派生自具体类。如果派生自具体类,就会依赖具体类。试着派生自接口或抽象类。
  • 不要覆盖基类中已经实现的方法。基类中已经实现的方法应当被所有子类共享,否则就不适合作为基类。

问题场景

有一个Pizza连锁店系统,总店希望各分店制作的pizza具有当地特色,比如同样是芝士披萨,纽约的披萨饼薄,芝加哥的饼厚。但是制作流程要和总店一致:烘烤、切片、装盒的方式。

类图

其实这个例子不怎么好,这里的工厂方法为“参数化工厂方法”,每个工厂负责创建多个产品(纽约披萨店要创建芝士、蛤蜊等多种口味的披萨)。正常使用的是每个工厂只产生一种产品,不需要参数,有新产品时增加相应的工厂。
在这里插入图片描述

代码

在这里插入图片描述

//工厂
public abstract class PizzaStore {//对产品进行操作,不需要关心具体是什么产品public Pizza orderPizza(String type) {Pizza pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}//工厂方法————这个方法就是工厂public abstract Pizza createPizza(String type);
}
//工厂子类
public class NYPizzaStore extends PizzaStore {@Override//参数化工厂方法,一个工厂负责创建多个产品public Pizza createPizza(String type) {switch (type) {case "Cheese":return new NYCheesePiz();case "Bacon":return new NYBaconPizza();default:return null;}}
}
//抽象产品
public class Pizza {public void prepare() {System.out.println( "Pizza is preparing...");}public void bake() {}public void cut() {}public void box() {}
}
//具体产品
public class NYCheesePiz extends Pizza {public NYCheesePiz() {}
}
//具体产品
public class NYBaconPizza extends Pizza {
}

抽象工厂模式

问题场景

不同地区的pizza店所采用的原料一般也不一样,比如纽约店使用新鲜的蛤蜊,芝加哥店使用冷冻的蛤蜊,它们使用的面粉也不一样······我们需要建造工厂来生产pizza的原料家族,并在制作pizza时使用这些工厂提供原料。

模式定义

抽象工厂模式 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

  • 抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。
  • 客户持有抽象工厂的引用,运行时使用具体工厂。

类图

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

代码

在这里插入图片描述

//抽象工厂
public interface CondiAbstrFactory {//各个原料使用单独的工厂方法创建public Meet createMeet();public Cheese createCheese();public Clam createClam();
}
public class NYCondiFactory implements CondiAbstrFactory {@Overridepublic Meet createMeet() {return new NYMeet();}@Overridepublic Cheese createCheese() {return new NYCheese();}@Overridepublic Clam createClam() {return new NYClam();}}
public abstract class Pizza {Cheese cheese;Meet meet;Clam clam;public abstract void prepare();public void bake();
}

通过工厂对象创建产品

//使用工厂创建原料
public class CheesePizza extends Pizza {public CheesePizza(CondiAbstrFactory condiAbstrFactory) {this.cheese = condiAbstrFactory.createCheese();this.meet = condiAbstrFactory.createMeet();}@Overridepublic void prepare() {}
}
//和上面一样,用工厂方法创建pizza
public abstract class PizzaStore {public Factory.AbstractFactory.Pizza orderPizza(String type) {Pizza pizza = createPizza(type);return pizza;}//工厂方法public abstract Factory.AbstractFactory.Pizza createPizza(String type);
}
public class NYPizzaStore extends PizzaStore {//使用抽象工厂的具体工厂//通过传入工厂制造不同的产品@Overridepublic Pizza createPizza(String type) {CondiAbstrFactory condiAbstrFactory = new NYCondiFactory();switch (type) {case "cheese":return new CheesePizza(condiAbstrFactory);//return new NYCheesePizza();case "clam":return new ClamPizza(condiAbstrFactory);//return new NYClamPizza();default:return null;}}
}

工厂方法模式v.s. 抽象工厂模式

工厂方法模式 抽象工厂模式
实现方式工厂方法模式使用继承,将具体类型的实例化放到子类中。 抽象工厂模式使用组合,抽象工厂提供创建产品家族(或一组相关产品)的工厂方法,具体工厂实现创建这些产品的方法。通过抽象工厂中的方法创建对象。客户使用具体工厂。
适用场景不知道将来要实例化哪些具体类型时可以使用工厂方法。 有一组相关产品要创建时使用抽象工厂。将这些创建的方法放到一个接口中。
开闭原则支持度高,每增加一个产品就增加一个工厂。支持度低,增加产品时要修改接口。
抽象工厂模式中的具体工厂实现工厂方法创建产品

这篇关于《HeadFirst设计模式》(4)——工厂模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/404908

相关文章

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

模版方法模式template method

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/template-method 超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 上层接口有默认实现的方法和子类需要自己实现的方法

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

《x86汇编语言:从实模式到保护模式》视频来了

《x86汇编语言:从实模式到保护模式》视频来了 很多朋友留言,说我的专栏《x86汇编语言:从实模式到保护模式》写得很详细,还有的朋友希望我能写得更细,最好是覆盖全书的所有章节。 毕竟我不是作者,只有作者的解读才是最权威的。 当初我学习这本书的时候,只能靠自己摸索,网上搜不到什么好资源。 如果你正在学这本书或者汇编语言,那你有福气了。 本书作者李忠老师,以此书为蓝本,录制了全套视频。 试

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

springboot实战学习(1)(开发模式与环境)

目录 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 (3)前端 二、开发模式 一、实战学习的引言 (1)前后端的大致学习模块 (2)后端 Validation:做参数校验Mybatis:做数据库的操作Redis:做缓存Junit:单元测试项目部署:springboot项目部署相关的知识 (3)前端 Vite:Vue项目的脚手架Router:路由Pina:状态管理Eleme

状态模式state

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/state 在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。 在状态模式中,player.getState()获取的是player的当前状态,通常是一个实现了状态接口的对象。 onPlay()是状态模式中定义的一个方法,不同状态下(例如“正在播放”、“暂停

软件架构模式:5 分钟阅读

原文: https://orkhanscience.medium.com/software-architecture-patterns-5-mins-read-e9e3c8eb47d2 软件架构模式:5 分钟阅读 当有人潜入软件工程世界时,有一天他需要学习软件架构模式的基础知识。当我刚接触编码时,我不知道从哪里获得简要介绍现有架构模式的资源,这样它就不会太详细和混乱,而是非常抽象和易