设计模式--工厂模式

2023-11-12

总的说来,工厂模式有两种:工厂方法和抽象工厂。

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化方法推迟到子类。利用工厂方法创建对象,通常需要继承一个类,并覆盖它的工厂方法。

举例如下(还是来自《Head First 设计模式》中的例子):

1.工厂方法

现在我们要买一个NY风味的Cheese Pizza,那么首先要得到一个生产NY风味的Pizza的工厂,然后点菜(传入需要的风味名称:”cheese“)

PizzaStore nyStore = new NYPizzaStore();
Pizza pizza1 = nyStore.orderPizza("cheese");

NYPizzaStore是生产NY风味Pizza的工厂,它继承自PizzaStore。提供了一个接口抽象方法
abstract Pizza creatPizza(String type)
根据传入的参数,生产相应类型的Pizza。

PizzaStore定义如下:

import edu.zju.www.Product.Pizza;;

public abstract class PizzaStore {
	protected abstract Pizza creatPizza(String type);             //这里提供了一个接口,让子类实现。从而到达了让子类去决定实例化类型的目的!
	public Pizza orderPizza(String type){
		Pizza pizza	;
		pizza = creatPizza(type);
		pizza.prepare();
		pizza.cut();
		pizza.box();
		return pizza;
	}
}

NYPizza覆盖了:

public Pizza creatPizza

其定义如下:

public class NYPizzaStore extends PizzaStore {

	@Override
	public Pizza creatPizza(String item) {          //这里是具体生产的方法,为了简单起见,只生产一种风味cheese
		// TODO Auto-generated method stub
		if(item.equals("cheese")){
			return new NYStyleCheesePizza();
		}else 
			return null; 
		}
	}

产品是Pizza。

Pizza的定义如下:

import java.util.ArrayList;

public abstract class Pizza {
	String name;
	String dough;
	String sauce;
	ArrayList topping = new ArrayList();
	public void prepare(){
		System.out.println("preparing " + name);
		System.out.println("Tossing dough...");
		System.out.println("Adding sauce...");
		System.out.println("Adding toppings:");
		for(int i = 0; i < topping.size();i++){
			System.out.println("  " + topping.get(i));
		}
	}
	public void bake(){
		System.out.println("baking at 350");
	}
	public void cut(){
		System.out.println("cutting the pizza into dialognal slices");
	}
	public void box(){
		System.out.println("Place the pizza into box");
	}
	public String getName(){
		return name;
	}
}
NY风格的CheesePizza继承自Pizza,定义如下:

public class NYStyleCheesePizza extends Pizza {
	public NYStyleCheesePizza(){
		name = "NY Syle Sauce and Cheese Pizza";
		dough = "Thin Crust Dough";
		sauce = "Marina Sauce";
		topping.add("Grated Regginao Cheese");
	}
}

运行结果:

preparing NY Syle Sauce and Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
  Grated Regginao Cheese
cutting the pizza into dialognal slices
Place the pizza into box


2.抽象工厂

通过抽象工厂所提供的接口,可以创建产品的家族而不要指定具体的类。(抽象工厂提供的接口,就是为子类搭好了框架,所以所有的子类看起来本质上都一样,只是表现形式不一样。

假设,生产Pizza需要3种原料:Dough, Sauce, Cheese。那么,就可以定义一个抽象工厂:PizzaIngredientFactoy

public interface PizzaIngredientFactoy {
	public Dough createDough();

	public Sauce createSauce();

	public Cheese createCheese();
}

而具体的生产NYPizzaIngredient的工厂NYPizzaIngredientFactoty集成了PizzaIngredientFactoy:

public class NYPizzaIngredientFactoty implements PizzaIngredientFactoy {

	@Override
	public Dough createDough() {
		// TODO Auto-generated method stub
		return new DoughNY();
	}

	@Override
	public Sauce createSauce() {
		// TODO Auto-generated method stub
		return new SauceNY();
	}

	@Override
	public Cheese createCheese() {
		// TODO Auto-generated method stub
		return new CheeseNY();
	}

}

当然,为了完善程序,自己还需要定义Dough, DoughNY, Sauce, SauceNY, Cheese, CheeseNY。(NY就是New york,代表new jork风味的Pizza)

这回Pizza的类定义如下:

public abstract class Pizza {
	Dough dough;
	Sauce sauce;
	Cheese cheese;
	public abstract void prepare();
}

具体类CheesePizza定义如下:

注意CheesePizza类使用了一个常用的手法:组合

public class CheesePizza extends Pizza {
	PizzaIngredientFactoy ingredientFactory;               //注意这里!!!!使用了组合

	public CheesePizza(PizzaIngredientFactoy ingredientFactory) {
		this.ingredientFactory = ingredientFactory;
	}

	@Override
	public void prepare() {
		// TODO Auto-generated method stub
		System.out.println("Preparing.... ");
		dough = ingredientFactory.createDough();
		sauce = ingredientFactory.createSauce();
		cheese = ingredientFactory.createCheese();
	}
}

最后,《Head First 设计模式》总结了两个方法的不同(有面试题目问到哦)

相同点:

工厂方法与抽象工厂都负责对象的创建,都是力图将类型的定义延迟到子类中(由子类来决定创建的类型)

不同点:

工厂方法使用继承,而抽象工厂使用组合:

可以看到,具体产品CheesePizza类中有一个Factory;

而在工厂方法中,要创建CheesePizza,首先要在外面自己创造一个Factory,然后调用工厂的创建方法并传入参数。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计模式--工厂模式 的相关文章

  • str_ireplace 与 str_replace 一样工作

    我需要用 url 字符串中的小 ascii 字符替换所有本地字符 包括大写字母 str echo str ireplace array array c c d s z str 结果 c c d s z 我期望 c c d s z c c d
  • 在 Swift 中删除字符串中第一个字符的最简洁方法是什么?

    我想删除字符串中的第一个字符 到目前为止 我想到的最简洁的事情是 display text display text substringFromIndex advance display text startIndex 1 我知道我们不能用
  • 替换 XSLT 中的特殊字符

    我想从 XSLT 中的字符串中删除字母以外的字符 例如
  • 如何计算一组字符串的最短唯一前缀?

    这是一个非常常见的算法命令行解析 给定一组预定义的长选项名称 计算唯一标识这些选项之一的最短前缀 例如 对于以下选项 help hostname portnumber name polymorphic 这将是输出 he ho por n p
  • Java ArrayList 的 (ArrayList).toString 的相反是什么?

    我正在使用toString的方法ArrayList储藏ArrayList数据到字符串中 我的问题是 我该如何走另一条路 是否有现有的方法可以解析中的数据String实例返回到ArrayList 最简洁的答案是不 没有简单的方法可以从字符串中
  • 在字符串中每个字母后面添加数字

    我有几个具有固定格式的字符串 格式为一个字母后跟一个数字 例如 A3B1C7D1 但是 如果字母后面的数字为 1 则字符串将写为 A3BC7D 我想做的是插入数字 1 然后将字符串转换为A3BC7D to A3B1C7D1 我的示例数据是
  • 来自字符串的文件大小

    我如何从 php 中的字符串中获取 文件大小 我将字符串作为 blob 放入 mysql 数据库中 并且需要存储 blob 的大小 我的解决方案是创建一个临时文件并将字符串放入临时文件中 现在我可以从 字符串 中获取文件大小 但这个解决方案
  • C# 从带引号的字符串中删除分隔符

    我正在编写一个程序 必须从文本文件中带引号的字符串中删除分隔符 例如 Hello my name is world 必须 Hello my name is world 起初这听起来很简单 我认为是这样 但是您需要检测引号何时开始 何时结束
  • 编译错误:尝试在函数调用中指定参数类型时出现“预期在 ' ' 之前出现主表达式”

    当我编译我的程序时 我收到以下错误消息 stringPerm cpp In function int main stringPerm cpp 12 error expected primary expression before word
  • 如何在Powershell控制台中分配多行字符串

    当我在 powershell 控制台中输入此内容时 test Test Test 并且输入多次 它会一直打印 gt gt 所以我永远无法完成命令 该怎么办 应该是行中的第一件事 或者它被认为只是字符串的一部分 test Test Test
  • Grep 模式匹配用双引号括起来的小写字符串

    我在 grep 方面遇到了一些问题 我似乎无法弄清楚 我试图在一组源文件中搜索用双引号 C 字符串 括起来的小写单词的所有实例 使用 bash 和 gnu grep grep e a z cpp 没有给我任何匹配项 而 grep e a z
  • Python 将字符串组合成尽可能短的字符串?

    如果我有一个字符串列表 我想将它们组合成一个具有重叠字符的字符串 如果没有剩余的重叠字符串 请将其添加到末尾 这是一个过于简化的版本 input one two output twone 我正在寻找一种方法来对输入列表中的任意数量的字符串执
  • 为什么 Java 和 .NET 中的字符串不能是可变的?

    为什么他们决定制作String在 Java 和 NET 以及其他一些语言 中是不可变的 他们为什么不让它可变呢 根据有效的Java http www oracle com technetwork java effectivejava 136
  • 如何从字符串中分离字符和数字部分

    例如 我想分开 OS234 to OS and 234 AA4230 to AA and 4230 我使用了以下简单的解决方案 但我确信应该有一个更有效和更强大的解决方案 private void demo string cell ABCD
  • Exit() 时是否调用基本对象析构函数?

    我意识到这个问题已经出现过几次 但我试图获得上述问题的明确答案 但我不断遇到相互矛盾的信息 我需要知道的是 当我使用 exit 时 基本类对象是否被破坏 我知道需要删除动态内存 但我的意思更像是 include
  • 将类对象放置在向量中?

    我注意到我可以将一个类放置在一个向量中 这是我的程序 我收到以下错误 out blackjack exe blackjack obj blackjack obj error LNK2019 unresolved external symbo
  • 不同 C++ 文件中的相同类名

    如果两个 C 文件具有相同名称的类的不同定义 那么当它们被编译和链接时 即使没有警告也会抛出一些东西 例如 a cc class Student public std string foo return A void foo a Stude
  • 检查字符串是否编码为 UTF-8

    function seems utf8 str length strlen str for i 0 i lt length i c ord str i if c lt 0x80 n 0 0bbbbbbb elseif c 0xE0 0xC0
  • 在打字稿中获取类的键

    我有一个包含很多方法的类 我们称之为 myClass 我这样称呼它 myClass key 有没有办法从 key 获取可能的值 我希望有类似 keyof myClass 的东西 但我得到 myClass 引用一个值 但在这里被用作类型 问题
  • 如何缩短 PHP if 语句?

    我有一个 if 语句 我需要将单个字符串与许多不同的选项进行比较 我在下面发布的代码非常清楚地表明了我的意思 我知道有两种方法可以做到这一点 但另一种甚至更长 那么 是否有任何函数可以以更短的方式实现类似的功能 我的要求可能看起来很愚蠢 但

随机推荐

  • Vite创建Vue项目常用的vite.config.ts配置

    import fileURLToPath URL from node url import defineConfig loadEnv from vite import vue from vitejs plugin vue import ba
  • 我来了,在这里起航

    五一过后 这济南的天全然没有了泉城该有的灵秀 夜里恼人的大风 总是肆无忌惮的闹一晚上 而这忽冷忽热的交替 却是让好些人陷入了穿秋裤脱秋裤的 噩梦 中 别看这几日热的紧 好歹有个晴朗的天空 据说过几日又是大雨倾盆的节奏 这济南的春啊 总是让人
  • 后台添加cookie,前端jsp获取不到

    在开发中遇到问题 后台 Cookie c new Cookie Cookie 11111111111111111111 c setPath response addCookie c 在前端jsp获取不到方法 Cookie cc reques
  • laravel8 实现签到功能案例

    本文是个案例 先来数据库 用户表 CREATE TABLE users id bigint 20 unsigned NOT NULL AUTO INCREMENT name varchar 255 COLLATE utf8mb4 unico
  • javascript的类型

    Javascript的类型分为两类 原始类型和对象类型 原始类型包括数字 字符串 布尔值 null和undefined ES6新增了symbol 数字 字符串和布尔值这三种原始类型可以转成包装对象 其中只有字符串的包装对象会产生可枚举的实义
  • 【iMovie】Error: RequestCVPixelBufferForFrame returned: 3 for absolute frame

    解决方案 删掉黑屏部分
  • 关于C语言中的重点转义字符详解

    一 了解有哪些常见的转义字符 首先 我们知道在C语言中有许多转义字符 接下来我将一些常见的转义字符罗列下来 a n t ddd xdd 二 依次介绍一下每个转义字符的具体作用 在书写连续多个问号后 防止他们被解析成三字母词 看代码 prin
  • Typora + PicGo + Gitee 搭建免费图床

    搭建准备 本次搭建过程需要以下介质 Typora PicGo Gitee GitHub 免费 Typora Typora 是一款 markdown 编辑器 支持几乎所有的 markdown 格式 神器 支持 macOS Windows Li
  • matlab74汉明码纠错,基于MATLAB汉明码设计与实现

    实验报告书 汉明码设计与实现 汉明码编译码器系统 班级 姓名 学号 一 实验原理描述 1 1汉明码编码原理 一般来说 若汉明码长为n 信息位数为k 则监督位数r n k 若希望用r 个监督位构造出r 个监督关系式来指示一位错码的n 种可能位
  • 数据结构笔记——第三章 栈和队列

    3 1 栈 3 1 1 栈的逻辑结构 1 栈 栈是限定仅在表尾进行插入和删除操作的线性表 允许插入和删除的一端称为栈顶 另一端称为栈底 不含任何数据元素的栈称为空栈 栈中元素除了具有线性关系外 还具有后进先出的特性 2 栈的抽象数据类型定义
  • 宝塔重置密码 mysql_linux宝塔面板安装 宝塔重置密码等常用命令

    安装宝塔 Centos安装脚本 yum install y wget wget O install sh http download bt cn install install sh sh install sh Ubuntu Deepin安
  • Unity 使用 Visual Studio 调试 Android 真机

    开始之前 保证自己能够build 出apk 一 Build Settings 设置 二 点击Build And Run 三 利用vs 调试代码 我就是想调试代码 但是 就是这个AndroidPlayer 一直出不来 卡了很久 我是这么解决的
  • ifconfig命令及详细介绍

    在 实体机上 ifconfig 命令用于 显示或配置网络设备 网络接口卡 或修改 以CentOS 7为例 ifconfig a 所有网卡信息 一 显示内容分析 1 ens33 以太网接口 virbr0 virbr nic类似 ens33 f
  • 灰度发布、蓝绿部署、金丝雀都是啥?

    目录 滚动部署 蓝绿发布 为什么还需要蓝绿 金丝雀发布 canary 金丝雀和蓝绿的对比 灰度发布 A B Test 实现 kubernetes istio spring cloud 网关 参考 滚动部署 在滚动部署中 应用的新版本逐步替换
  • Textbooks Are All You Need II: phi-1.5 technical report

    本文是LLM系列文章 针对 Textbooks Are All You Need II phi 1 5 technical report 的翻译 教科书是你所需要的一切 phi 1 5技术报告 摘要 1 引言 2 技术规范 3 基准结果 4
  • 大数据平台搭建

    一 安装前准备 1 查看防火墙状态 2 关闭防火墙 分别在三台虚拟机上操作 root slave2 systemctl status firewalld service firewalld service firewalld dynamic
  • 全国大学生电子设计大赛赛前必备PID控制平衡车代码-pid实例

    全国大学生电子设计大赛平衡车完整代码arduino PID控制实例 This code is used for connecting arduino to serial mpu6050 module and test in arduino
  • 大话Stable-Diffusion-Webui-客制化主题(四)

    文章目录 目标 效果 开始 重要说明 单选框以及复选框图标样式更改 gradio主题构建器上传主题方式 代码上传主题方式 目标 在DIY的主题中更改gradio单选框组件以及复选框组件的勾选后图标样式 效果 开始 笔者在使用gradio的主
  • CORS跨域请求及实现机制

    一 什么是CORS CORS是一个W3C标准 全称是 跨域资源共享 Cross origin resource sharing 它允许浏览器向跨源服务器 发出XMLHttpRequest请求 从而克服了AJAX只能同源使用的限制 只要服务器
  • 设计模式--工厂模式

    总的说来 工厂模式有两种 工厂方法和抽象工厂 工厂方法模式定义了一个创建对象的接口 但由子类决定要实例化的类是哪一个 工厂方法让类把实例化方法推迟到子类 利用工厂方法创建对象 通常需要继承一个类 并覆盖它的工厂方法 举例如下 还是来自 He