【中秋赏码】Java程序员用中文编程教你做月饼。
一、前言
什么? 花好月圆之日你还在写Bug? 什么? 花好月圆之日你还在加班? 什么? 花好月圆之日你还没有女朋友?
没关系我也没有😭。不过还好, 至少公司还发了一盒月饼。那我们就开始赏月吧。等等… 我们的主题是中秋赏码。
本篇小编教你用中文写出具有中国特色的制造月饼的代码工艺吧, 我们中秋赏码。在赏码的过程中,顺便学习几个设计模式。来看看有几个是你平时常用的吧。
需求是这样的:
有一个食品车间,中秋卖月饼,端午卖粽子。这不马上到中秋了嘛。今年一共会生产3种口味的月饼。【五仁月饼】【莲蓉蛋黄月饼】【枣泥月饼】。交给你来设计系统,你会怎么设计呢?
需求设计
那么我们如何使用设计模式来生产月饼呢? 在聊设计模式之前我们先思考下如何高效做月饼? 最后再用设计模式进行优化。
首先我们先定义一个食品工厂,食品工厂不可能只卖月饼,中秋卖月饼,端午卖粽子。至于让工厂生产什么,却绝于季节,所以我们要定义一个策略【策略模式】。
每个食品车间,生产的食品,味道可能也是不同的,食品加工工艺也是不同的。为每个食品车间定义一个流水线接口, 相同食品一定会有通用的操作流程,所以定义一个标准的月饼生产模版类,模版类中提供通用的流程。
具体的口味只是生产月饼中的步骤的不同,所以交给子类来实现。
所以最终这里我们会用到三种设计模式。
- 工厂模式 + 策越模式
- 抽象模版
二、中秋赏码
2.1 目录结构
.
├── main
│ ├── java
│ │ └── cn
│ │ └── lxchinesszz
│ │ ├── 流水线
│ │ │ ├── 五仁月饼流水线.java
│ │ │ ├── 月饼制作流水线.java
│ │ │ ├── 月饼流水线.java
│ │ │ ├── 枣泥月饼流水线.java
│ │ │ ├── 流水线.java
│ │ │ └── 莲蓉蛋黄月饼流水线.java
│ │ ├── 车间
│ │ │ ├── 月饼生产车间.java
│ │ │ └── 食品车间.java
│ │ ├── 食品
│ │ │ ├── 食品.java
│ │ │ └── 月饼.java
│ │ ├── 食品口味.java
│ │ └── 食品工厂.java
│ └── resources
└── test
└── java
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
2.2 定义食品工厂
关键字: 策略模式
具体工厂生产什么,由使用方自己决定。
public class 食品工厂 {
private 食品车间 车间;
public 食品工厂(食品车间 车间) {
this.车间 = 车间;
}
public 食品 生产食品(食品口味 口味) {
return 车间.生产食品(口味);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2.3 定义食品车间
关键字: 口味策略
public interface 食品车间 {
食品 生产食品(食品口味 口味);
}
public class 月饼生产车间 implements 食品车间 {
@Override
public 食品 生产食品(食品口味 口味) {
流水线 月饼流水线;
if (食品口味.五仁.equals(口味)) {
月饼流水线 = new 五仁月饼流水线();
} else if (食品口味.枣泥.equals(口味)) {
月饼流水线 = new 枣泥月饼流水线();
} else {
月饼流水线 = new 莲蓉蛋黄月饼流水线();
}
System.out.println("月饼车间开工了,开始生产月饼了");
食品 月饼 = 月饼流水线.生成食品();
System.out.println("【" + 月饼 + "】,生产好了");
return 月饼;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
2.4 定义流水线
关键字: 抽象模版
月饼流水线实现了流水线的生产食品的接口, 并提供抽象的生产月饼的接口。交给子类去使用。在模版类中
可以定义统一的月饼生产流程
。而具体月饼口味的细节交给子类去实现。
public interface 流水线{
食品 生成食品();
}
public abstract class 月饼流水线 implements 流水线 {
@Override
public 食品 生成食品() {
System.out.println("月饼生产作业开始:和面");
食品 食品 = 生成月饼();
System.out.println("月饼烤制流程结束");
System.out.println("开始烤制完成开始打包装箱");
return 食品;
}
public abstract 食品 生成月饼();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
2.5 具体口味实现
关键字: 单一职责
月饼中口味的不同,交给子类的具体的实现,每种口味之间没有依赖关系。完全的解耦。
- 五仁月饼
public class 五仁月饼流水线 extends 月饼流水线 {
@Override
public 月饼 生成月饼() {
System.out.println("开始生成五仁月饼");
return new 月饼(食品口味.五仁);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 枣泥月饼
public class 枣泥月饼流水线 extends 月饼流水线 {
@Override
public 月饼 生成月饼() {
System.out.println("开始生成枣泥月饼");
return new 月饼(食品口味.枣泥);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 莲蓉蛋黄月饼
public class 莲蓉蛋黄月饼流水线 extends 月饼流水线 {
@Override
public 月饼 生成月饼() {
System.out.println("开始生成莲蓉蛋黄月饼");
return new 月饼(食品口味.莲蓉蛋黄);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
三、总结
我们的设计的时候,可以思考这些地方。在这些地方进行优化和设计。
- 单一职责,高内聚低耦合,一个类只做一个事情,尽量避免耦合。
- 接口是自上而下设计的,你想要的能力究竟是什么?
- 抽象是自下而上设计的,千万不要搞反了,能公用的或者是能抽象出标准流程的可以使用模版来定义。
- 考虑扩展性。暂时想不到可以不考虑,没必要为了扩展性的而天马行空的去设计,得不偿失。
只要记住这几个知识点,相信你的设计能力也会有很大的提升。下面我们来解释这几句话。各位观众老爷如果还有设计的小妙招,欢迎留言评论。
3.1 单一职责,接口设计
月饼口味的设计,每种口味的做法是不相同的,所以我们先定义一个生产月饼的接口。具体的实现都是细节,
每种口味的要保持单一职责,这样的好处是,当你再修改一个口味的时候,是一定不会影响到其他口味的月饼生成的。
如果只考虑这些可能我们的图就像下面这样。
public class 五仁月饼流水线 extends 月饼流水线 {
@Override
public 月饼 生成月饼() {
System.out.println("开始生成五仁月饼");
return new 月饼(食品口味.五仁);
}
}
public class 枣泥月饼流水线 extends 月饼流水线 {
@Override
public 月饼 生成月饼() {
System.out.println("开始生成枣泥月饼");
return new 月饼(食品口味.枣泥);
}
}
public class 莲蓉蛋黄月饼流水线 extends 月饼流水线 {
@Override
public 月饼 生成月饼() {
System.out.println("开始生成莲蓉蛋黄月饼");
return new 月饼(食品口味.莲蓉蛋黄);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
3.2 抽象是自下而上设计的
抽象是自下而上设计,不可能在不清楚细节的情况下,上去就进行抽象的。而一定是在细节已经设计好了的情况下,再进行抽象来优化流程。
所以我们思考: 不管月饼的口味是什么,他们都是月饼。一定有最终相同的处理流程。比如说月饼包装,月饼都需要进行烤制。这个时候我们就要在这三种口味的月饼上进行抽象了,他们有什么相同点? 相同点都抽象出来,形成标准的模版。
所以我们在上面设计一个抽象类,抽象类中做公用的逻辑。
就如果上面的代码,我们在抽象类中,去和面、烤制、和打包装箱。
public abstract class 月饼流水线 implements 流水线 {
@Override
public 食品 生成食品() {
System.out.println("月饼生产作业开始:和面");
食品 食品 = 生成月饼();
System.out.println("月饼烤制流程结束");
System.out.println("开始烤制完成开始打包装箱");
return 食品;
}
public abstract 食品 生成月饼();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3.3 考虑扩展性
工厂不可能只生成月饼,这里使用策略设计,生产什么你说了算。
public class 食品工厂 {
private 食品车间 车间;
public 食品工厂(食品车间 车间) {
this.车间 = 车间;
}
public 食品 生产食品(食品口味 口味) {
return 车间.生产食品(口味);
}
public static void main(String[] args) {
new 食品工厂(new 月饼生产车间()).生产食品(食品口味.枣泥);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
那么你get到,你想要的知识点了吗? 那么你准备好跟我一起Coding了吗?
推荐环节
最后小编还写了免费的关于Mybatis的源码学习系列和手撸JavaRPC系列,从网络通信开始,从0到1实现一个RPC框架爱,如果感兴趣的话,点个关注吧,交个朋友吧。
天下代码一大抄,抄来抄去有提高,看你会抄不会抄,跟我一起来写代码吧。
- 第01篇:手写JavaRPC框架之思路分析
- 第02篇:手写JavaRPC框架之设计思路
- 第03篇: 手写JavaRPC框架之搞定序列化
- 第04篇:手写JavaRPC框架之搞定网络通信
- 第05篇:手写JavaRPC框架之执行层思路
文章来源: springlearn.blog.csdn.net,作者:西魏陶渊明,版权归原作者所有,如需转载,请联系作者。
原文链接:springlearn.blog.csdn.net/article/details/126594782
- 点赞
- 收藏
- 关注作者
评论(0)