• 【中秋赏码】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

    三、总结

    我们的设计的时候,可以思考这些地方。在这些地方进行优化和设计。

    1. 单一职责,高内聚低耦合,一个类只做一个事情,尽量避免耦合。
    2. 接口是自上而下设计的,你想要的能力究竟是什么?
    3. 抽象是自下而上设计的,千万不要搞反了,能公用的或者是能抽象出标准流程的可以使用模版来定义。
    4. 考虑扩展性。暂时想不到可以不考虑,没必要为了扩展性的而天马行空的去设计,得不偿失。

    只要记住这几个知识点,相信你的设计能力也会有很大的提升。下面我们来解释这几句话。各位观众老爷如果还有设计的小妙招,欢迎留言评论。

    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框架爱,如果感兴趣的话,点个关注吧,交个朋友吧。

    天下代码一大抄,抄来抄去有提高,看你会抄不会抄,跟我一起来写代码吧。

  • 相关阅读:
    Es中索引的删除操作
    pdfjs-dist的进阶使用:手动触发pdf文件跳转到指定页码
    尚硅谷Vue系列教程学习笔记(5)
    5分钟使用ssl证书免费配置任意域名的 https
    银河麒麟V10系统 syslog和kern.log文件过大问题解决,定时清理日志文件
    会议OA之我的会议(排座&送审)
    2021.06 编程题 36【Python二级题目解析】
    【无标题】
    2023 年高教社杯全国大学生数学建模竞赛获奖名单(初稿)公示
    【前端】IOS微信浏览器点击右上角遮罩实现
  • 原文地址:https://blog.csdn.net/Message_lx/article/details/126594782