Java 23种设计模式系列之——实战原型模式

JAVA设计模式总结之23种设计模式 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。 阅读详情

设计模式的分类----实战原型模式

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:Java 23种设计模式系列之——实战桥接模式Java 23种设计模式系列之——实战桥接模式

一、前言

老板你加钱我的代码能飞

程序员这份工作里有两种人;一类是热爱喜欢的、一类是仅当成工作的。而喜欢代码编程的这部分人会极其主动学习去丰富自己的羽翼,也非常喜欢对技术探索力求将学到的知识赋能到平时的业务需求开发中。对于这部分小伙伴来说上班写代码还能赚钱真的是幸福!

怎么成为喜欢编码都那部分人

无论做哪行那业你都喜欢,往往来自从中持续不断都获取成就感。就开发编程而言因为你的一行代码影响到了千千万万的人、因为你的一行代码整个系统更加稳定、因为你的一行代码扛过了所有秒杀等等,这样一行行的代码都是你日积月累学习到的经验。那如果你也想成为这样有成就感的程序员就需要不断的学习,不断的用更多的技能知识把自己编写的代码运用到更核心的系统。

方向不对努力白费

平常你也付出了很多的时间,但就是没有得到多少收益。就像有时候很多小伙伴问我,我是该怎么学一个我没接触过的内容。我的个人经验非常建议,先不要学太多理论性的内容,而是尝试实际操作下,把要学的内容做一些Demo案例出来。这有点像你买了个自行车是先拆了学学怎么个原理,还是先骑几圈呢?哪怕摔了跟头,但那都是必须经历后留下的经验。

同样我也知道很多人看了设计模式收获不大,这主要新人对没有案例或者案例不贴近实际场景没有学习方向导致。太空、太虚、太玄,让人没有抓手!

所以我开始编写以实际案例为着手的方式,讲解设计模式的文章,帮助大家成长的同时也让我自己有所沉淀!

二、开发环境

  1. JDK 1.8
  2. Idea + Maven
  3. 涉及工程三个
工程描述
itstack-demo-design-4-00场景模拟工程,模拟在线考试题库抽提打乱顺序
itstack-demo-design-4-01使用一坨代码实现业务需求,也是对ifelse的使用
itstack-demo-design-4-02通过设计模式优化改造代码,产生对比性从而学习

三、原型模式介绍

原型模式,图片来自 refactoringguru.cn

原型模式主要解决的问题就是创建重复对象,而这部分对象内容本身比较复杂,生成过程可能从库或者RPC接口中获取数据的耗时较长,因此采用克隆的方式节省时间。

其实这种场景经常出现在我们的身边,只不过很少用到自己的开发中,就像;

  1. 你经常Ctrl+C、Ctrl+V,复制粘贴代码。
  2. Java多数类中提供的API方法;Object clone()。
  3. 细胞的有丝分裂。

类似以上的场景并不少,但如果让你去思考平时的代码开发中,有用到这样的设计模式吗?确实不那么容易找到,甚至有时候是忽略了这个设计模式的方式。在没有阅读下文之前,也可以思考下哪些场景可以用到。

四、案例场景模拟

场景模拟;考试试卷

每个人都经历过考试,从纸制版到上机答题,大大小小也有几百场。而以前坐在教室里答题身边的人都是一套试卷,考试的时候还能偷摸或者别人给发信息抄一抄答案。

但从一部分可以上机考试的内容开始,在保证大家的公平性一样的题目下,开始出现试题混排更有做的好的答案选项也混排。这样大大的增加了抄的成本,也更好的做到了考试的公平性。

但如果这个公平性的考试需求交给你来完成,你会怎么做?

因为需要实现一个上机考试抽题的服务,因此在这里建造一个题库题目的场景类信息,用于创建;选择题、问答题。

1. 场景模拟工程

itstack-demo-design-4-00
└── src
    └── main
        └── java
            └── org.itstack.demo.design
                ├── AnswerQuestion.java
                └── ChoiceQuestion.java
  • 在这里模拟了两个试卷题目的类;ChoiceQuestion(选择题)、AnswerQuestion(问答题)。如果是实际的业务场景开发中,会有更多的题目类型,可以回忆一下你的高考试卷。

2. 场景简述

2.1 选择题

public class ChoiceQuestion {

    private String name;                 // 题目
    private Map<String, String> option;  // 选项;A、B、C、D
    private String key;                  // 答案;B

    public ChoiceQuestion() {
    }

    public ChoiceQuestion(String name, Map<String, String> option, String key) {
        this.name = name;
        this.option = option;
        this.key = key;
    }

    // ...get/set
}

2.2 问答题

public class AnswerQuestion {

    private String name;  // 问题
    private String key;   // 答案

    public AnswerQuestion() {
    }

    public AnswerQuestion(String name, String key) {
        this.name = name;
        this.key = key;
    }

    // ...get/set
}
  • 以上两个类就是我们场景中需要的物料内容,相对来说比较简单。如果你在测试的时候想扩充学习,可以继续添加一些其他物料(题目类型)。

五、用一坨坨代码实现

今天的实现方式没有ifelse了,但是没有一个类解决不了的业务,只要你胆大!

在以下的例子中我们会按照每一个用户创建试卷的题目,并返回给调用方。

1. 工程结构

itstack-demo-design-4-01
└── src
    └── main
        └── java
            └── org.itstack.demo.design
                └── QuestionBankController.java
  • 一个类几千行的代码你是否见过,嚯?那今天就再让你见识一下有这样潜质的类!

2. 一把梭实现需求

public class QuestionBankController {

    public String createPaper(String candidate, String number) {

        List<ChoiceQuestion> choiceQuestionList = new ArrayList<ChoiceQuestion>();
        List<AnswerQuestion> answerQuestionList = new ArrayList<AnswerQuestion>();

        Map<String, String> map01 = new HashMap<String, String>();
        map01.put("A", "JAVA2 EE");
        map01.put("B", "JAVA2 Card");
        map01.put("C", "JAVA2 ME");
        map01.put("D", "JAVA2 HE");
        map01.put("E", "JAVA2 SE");

        Map<String, String> map02 = new HashMap<String, String>();
        map02.put("A", "JAVA程序的main方法必须写在类里面");
        map02.put("B", "JAVA程序中可以有多个main方法");
        map02.put("C", "JAVA程序中类名必须与文件名一样");
        map02.put("D", "JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来");

        Map<String, String> map03 = new HashMap<String, String>();
        map03.put("A", "变量由字母、下划线、数字、$符号随意组成;");
        map03.put("B", "变量不能以数字作为开头;");
        map03.put("C", "A和a在java中是同一个变量;");
        map03.put("D", "不同类型的变量,可以起相同的名字;");

        Map<String, String> map04 = new HashMap<String, String>();
        map04.put("A", "STRING");
        map04.put("B", "x3x;");
        map04.put("C", "void");
        map04.put("D", "de$f");

        Map<String, String> map05 = new HashMap<String, String>();
        map05.put("A", "31");
        map05.put("B", "0");
        map05.put("C", "1");
        map05.put("D", "2");

        choiceQuestionList.add(new ChoiceQuestion("JAVA所定义的版本中不包括", map01, "D"));
        choiceQuestionList.add(new ChoiceQuestion("下列说法正确的是", map02, "A"));
        choiceQuestionList.add(new ChoiceQuestion("变量命名规范说法正确的是", map03, "B"));
        choiceQuestionList.add(new ChoiceQuestion("以下()不是合法的标识符", map04, "C"));
        choiceQuestionList.add(new ChoiceQuestion("表达式(11+3*8)/4%3的值是", map05, "D"));
        answerQuestionList.add(new AnswerQuestion("小红马和小黑马生的小马几条腿", "4条腿"));
        answerQuestionList.add(new AnswerQuestion("铁棒打头疼还是木棒打头疼", "头最疼"));
        answerQuestionList.add(new AnswerQuestion("什么床不能睡觉", "牙床"));
        answerQuestionList.add(new AnswerQuestion("为什么好马不吃回头草", "后面的草没了"));

        // 输出结果
        StringBuilder detail = new StringBuilder("考生:" + candidate + "\r\n" +
                "考号:" + number + "\r\n" +
                "--------------------------------------------\r\n" +
                "一、选择题" + "\r\n\n");

        for (int idx = 0; idx < choiceQuestionList.size(); idx++) {
            detail.append("第").append(idx + 1).append("题:").append(choiceQuestionList.get(idx).getName()).append("\r\n");
            Map<String, String> option = choiceQuestionList.get(idx).getOption();
            for (String key : option.keySet()) {
                detail.append(key).append(":").append(option.get(key)).append("\r\n");
                ;
            }
            detail.append("答案:").append(choiceQuestionList.get(idx).getKey()).append("\r\n\n");
        }

        detail.append("二、问答题" + "\r\n\n");

        for (int idx = 0; idx < answerQuestionList.size(); idx++) {
            detail.append("第").append(idx + 1).append("题:").append(answerQuestionList.get(idx).getName()).append("\r\n");
            detail.append("答案:").append(answerQuestionList.get(idx).getKey()).append("\r\n\n");
        }

        return detail.toString();
    }

}
  • 这样的代码往往都非常易于理解,要什么程序就给什么代码,不面向对象,只面向过程。不考虑扩展性,能用就行。
  • 以上的代码主要就三部分内容;首先创建选择题和问答题到集合中、定义详情字符串包装结果、返回结果内容。
  • 但以上的代码有一个没有实现的地方就是不能乱序,所有人的试卷顺序都是一样的。如果需要加乱序也是可以的,但复杂度又会增加。这里不展示具体过多实现,只为后文对比重构。

3. 测试验证

接下来我们通过junit单元测试的方式验证接口服务,强调日常编写好单测可以更好的提高系统的健壮度。

编写测试类:

@Test
public void test_QuestionBankController() {
    QuestionBankController questionBankController = new QuestionBankController();
    System.out.println(questionBankController.createPaper("花花", "1000001921032"));
    System.out.println(questionBankController.createPaper("豆豆", "1000001921051"));
    System.out.println(questionBankController.createPaper("大宝", "1000001921987"));
}

结果:

考生:花花
考号:1000001921032
--------------------------------------------
一、选择题

第1题:JAVA所定义的版本中不包括
A:JAVA2 EE
B:JAVA2 Card
C:JAVA2 ME
D:JAVA2 HE
E:JAVA2 SE
答案:D

第2题:下列说法正确的是
A:JAVA程序的main方法必须写在类里面
B:JAVA程序中可以有多个main方法
C:JAVA程序中类名必须与文件名一样
D:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
答案:A

第3题:变量命名规范说法正确的是
A:变量由字母、下划线、数字、$符号随意组成;
B:变量不能以数字作为开头;
C:A和a在java中是同一个变量;
D:不同类型的变量,可以起相同的名字;
答案:B

第4题:以下()不是合法的标识符
A:STRING
B:x3x;
C:void
D:de$f
答案:C

第5题:表达式(11+3*8)/4%3的值是
A:31
B:0
C:1
D:2
答案:D

二、问答题

第1题:小红马和小黑马生的小马几条腿
答案:4条腿

第2题:铁棒打头疼还是木棒打头疼
答案:头最疼

第3题:什么床不能睡觉
答案:牙床

第4题:为什么好马不吃回头草
答案:后面的草没了


考生:豆豆
考号:1000001921051
--------------------------------------------
一、选择题

第1题:JAVA所定义的版本中不包括
A:JAVA2 EE
B:JAVA2 Card
C:JAVA2 ME
D:JAVA2 HE
E:JAVA2 SE
答案:D

第2题:下列说法正确的是
A:JAVA程序的main方法必须写在类里面
B:JAVA程序中可以有多个main方法
C:JAVA程序中类名必须与文件名一样
D:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
答案:A

第3题:变量命名规范说法正确的是
A:变量由字母、下划线、数字、$符号随意组成;
B:变量不能以数字作为开头;
C:A和a在java中是同一个变量;
D:不同类型的变量,可以起相同的名字;
答案:B

第4题:以下()不是合法的标识符
A:STRING
B:x3x;
C:void
D:de$f
答案:C

第5题:表达式(11+3*8)/4%3的值是
A:31
B:0
C:1
D:2
答案:D

二、问答题

第1题:小红马和小黑马生的小马几条腿
答案:4条腿

第2题:铁棒打头疼还是木棒打头疼
答案:头最疼

第3题:什么床不能睡觉
答案:牙床

第4题:为什么好马不吃回头草
答案:后面的草没了


考生:大宝
考号:1000001921987
--------------------------------------------
一、选择题

第1题:JAVA所定义的版本中不包括
A:JAVA2 EE
B:JAVA2 Card
C:JAVA2 ME
D:JAVA2 HE
E:JAVA2 SE
答案:D

第2题:下列说法正确的是
A:JAVA程序的main方法必须写在类里面
B:JAVA程序中可以有多个main方法
C:JAVA程序中类名必须与文件名一样
D:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
答案:A

第3题:变量命名规范说法正确的是
A:变量由字母、下划线、数字、$符号随意组成;
B:变量不能以数字作为开头;
C:A和a在java中是同一个变量;
D:不同类型的变量,可以起相同的名字;
答案:B

第4题:以下()不是合法的标识符
A:STRING
B:x3x;
C:void
D:de$f
答案:C

第5题:表达式(11+3*8)/4%3的值是
A:31
B:0
C:1
D:2
答案:D

二、问答题

第1题:小红马和小黑马生的小马几条腿
答案:4条腿

第2题:铁棒打头疼还是木棒打头疼
答案:头最疼

第3题:什么床不能睡觉
答案:牙床

第4题:为什么好马不吃回头草
答案:后面的草没了

Process finished with exit code 0
  • 以上呢就是三位考试的试卷;花花、豆豆、大宝,每个人的试卷内容是一样的这没问题,但是三个人的题目以及选项顺序都是一样,就没有达到我们说希望的乱序要求。
  • 而且以上这样的代码非常难扩展,随着题目的不断的增加以及乱序功能的补充,都会让这段代码变得越来越混乱。

六、原型模式重构代码

接下来使用原型模式来进行代码优化,也算是一次很小的重构。

原型模式主要解决的问题就是创建大量重复的类,而我们模拟的场景就需要给不同的用户都创建相同的试卷,但这些试卷的题目不便于每次都从库中获取,甚至有时候需要从远程的RPC中获取。这样都是非常耗时的,而且随着创建对象的增多将严重影响效率。

在原型模式中所需要的非常重要的手段就是克隆,在需要用到克隆的类中都需要实现 implements Cloneable 接口。

1. 工程结构

itstack-demo-design-4-02
└── src
    ├── main
    │   └── java
    │       └── org.itstack.demo.design
    │           ├── util
    │           │   ├── Topic.java
    │           │   └── TopicRandomUtil.java
    │           ├── QuestionBank.java
    │           └── QuestionBankController.java 
    └── test
         └── java
             └── org.itstack.demo.design.test
                 └── ApiTest.java

原型模式模型结构

原型模式模型结构

  • 工程中包括了核心的题库类QuestionBank,题库中主要负责将各个的题目进行组装最终输出试卷。
  • 针对每一个试卷都会使用克隆的方式进行复制,复制完成后将试卷中题目以及每个题目的答案进行乱序处理。这里提供了工具包;TopicRandomUtil

2. 代码实现

2.1 题目选项乱序操作工具包

/**
 * 乱序Map元素,记录对应答案key
 * @param option 题目
 * @param key    答案
 * @return Topic 乱序后 {A=c., B=d., C=a., D=b.}
 */
static public Topic random(Map<String, String> option, String key) {
    Set<String> keySet = option.keySet();
    ArrayList<String> keyList = new ArrayList<String>(keySet);
    Collections.shuffle(keyList);
    HashMap<String, String> optionNew = new HashMap<String, String>();
    int idx = 0;
    String keyNew = "";
    for (String next : keySet) {
        String randomKey = keyList.get(idx++);
        if (key.equals(next)) {
            keyNew = randomKey;
        }
        optionNew.put(randomKey, option.get(next));
    }
    return new Topic(optionNew, keyNew);
}
  • 可能你还记得上文里我们提供了Map存储题目选项,同时key的属性存放答案。如果忘记可以往上翻翻
  • 这个这个工具类的操作就是将原有Map中的选型乱序操作,也就是A的选项内容给B,B的可能给C,同时记录正确答案在处理后的位置信息。

2.2 克隆对象处理类

public class QuestionBank implements Cloneable {

    private String candidate; // 考生
    private String number;    // 考号

    private ArrayList<ChoiceQuestion> choiceQuestionList = new ArrayList<ChoiceQuestion>();
    private ArrayList<AnswerQuestion> answerQuestionList = new ArrayList<AnswerQuestion>();

    public QuestionBank append(ChoiceQuestion choiceQuestion) {
        choiceQuestionList.add(choiceQuestion);
        return this;
    }

    public QuestionBank append(AnswerQuestion answerQuestion) {
        answerQuestionList.add(answerQuestion);
        return this;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        QuestionBank questionBank = (QuestionBank) super.clone();
        questionBank.choiceQuestionList = (ArrayList<ChoiceQuestion>) choiceQuestionList.clone();
        questionBank.answerQuestionList = (ArrayList<AnswerQuestion>) answerQuestionList.clone();

        // 题目乱序
        Collections.shuffle(questionBank.choiceQuestionList);
        Collections.shuffle(questionBank.answerQuestionList);
        // 答案乱序
        ArrayList<ChoiceQuestion> choiceQuestionList = questionBank.choiceQuestionList;
        for (ChoiceQuestion question : choiceQuestionList) {
            Topic random = TopicRandomUtil.random(question.getOption(), question.getKey());
            question.setOption(random.getOption());
            question.setKey(random.getKey());
        }
        return questionBank;
    }

    public void setCandidate(String candidate) {
        this.candidate = candidate;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public String toString() {

        StringBuilder detail = new StringBuilder("考生:" + candidate + "\r\n" +
                "考号:" + number + "\r\n" +
                "--------------------------------------------\r\n" +
                "一、选择题" + "\r\n\n");

        for (int idx = 0; idx < choiceQuestionList.size(); idx++) {
            detail.append("第").append(idx + 1).append("题:").append(choiceQuestionList.get(idx).getName()).append("\r\n");
            Map<String, String> option = choiceQuestionList.get(idx).getOption();
            for (String key : option.keySet()) {
                detail.append(key).append(":").append(option.get(key)).append("\r\n");;
            }
            detail.append("答案:").append(choiceQuestionList.get(idx).getKey()).append("\r\n\n");
        }

        detail.append("二、问答题" + "\r\n\n");

        for (int idx = 0; idx < answerQuestionList.size(); idx++) {
            detail.append("第").append(idx + 1).append("题:").append(answerQuestionList.get(idx).getName()).append("\r\n");
            detail.append("答案:").append(answerQuestionList.get(idx).getKey()).append("\r\n\n");
        }

        return detail.toString();
    }

}

这里的主要操作内容有三个,分别是;

  • 两个append(),对各项题目的添加,有点像我们在建造者模式中使用的方式,添加装修物料。
  • clone() ,这里的核心操作就是对对象的复制,这里的复制不只是包括了本身,同时对两个集合也做了复制。只有这样的拷贝才能确保在操作克隆对象的时候不影响原对象。
  • 乱序操作,在list集合中有一个方法,Collections.shuffle,可以将原有集合的顺序打乱,输出一个新的顺序。在这里我们使用此方法对题目进行乱序操作。

2.4 初始化试卷数据

public class QuestionBankController {

    private QuestionBank questionBank = new QuestionBank();

    public QuestionBankController() {

        Map<String, String> map01 = new HashMap<String, String>();
        map01.put("A", "JAVA2 EE");
        map01.put("B", "JAVA2 Card");
        map01.put("C", "JAVA2 ME");
        map01.put("D", "JAVA2 HE");
        map01.put("E", "JAVA2 SE");

        Map<String, String> map02 = new HashMap<String, String>();
        map02.put("A", "JAVA程序的main方法必须写在类里面");
        map02.put("B", "JAVA程序中可以有多个main方法");
        map02.put("C", "JAVA程序中类名必须与文件名一样");
        map02.put("D", "JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来");

        Map<String, String> map03 = new HashMap<String, String>();
        map03.put("A", "变量由字母、下划线、数字、$符号随意组成;");
        map03.put("B", "变量不能以数字作为开头;");
        map03.put("C", "A和a在java中是同一个变量;");
        map03.put("D", "不同类型的变量,可以起相同的名字;");

        Map<String, String> map04 = new HashMap<String, String>();
        map04.put("A", "STRING");
        map04.put("B", "x3x;");
        map04.put("C", "void");
        map04.put("D", "de$f");

        Map<String, String> map05 = new HashMap<String, String>();
        map05.put("A", "31");
        map05.put("B", "0");
        map05.put("C", "1");
        map05.put("D", "2");
        
        questionBank.append(new ChoiceQuestion("JAVA所定义的版本中不包括", map01, "D"))
                .append(new ChoiceQuestion("下列说法正确的是", map02, "A"))
                .append(new ChoiceQuestion("变量命名规范说法正确的是", map03, "B"))
                .append(new ChoiceQuestion("以下()不是合法的标识符",map04, "C"))
                .append(new ChoiceQuestion("表达式(11+3*8)/4%3的值是", map05, "D"))
                .append(new AnswerQuestion("小红马和小黑马生的小马几条腿", "4条腿"))
                .append(new AnswerQuestion("铁棒打头疼还是木棒打头疼", "头最疼"))
                .append(new AnswerQuestion("什么床不能睡觉", "牙床"))
                .append(new AnswerQuestion("为什么好马不吃回头草", "后面的草没了"));
    }

    public String createPaper(String candidate, String number) throws CloneNotSupportedException {
        QuestionBank questionBankClone = (QuestionBank) questionBank.clone();
        questionBankClone.setCandidate(candidate);
        questionBankClone.setNumber(number);
        return questionBankClone.toString();
    }

}
  • 这个类的内容就比较简单了,主要提供对试卷内容的模式初始化操作(所有考生试卷一样,题目顺序不一致)。
  • 以及对外部提供创建试卷的方法,在创建的过程中使用的是克隆的方式;(QuestionBank) questionBank.clone();,并最终返回试卷信息。

3. 测试验证

编写测试类:

@Test
public void test_QuestionBank() throws CloneNotSupportedException {
    QuestionBankController questionBankController = new QuestionBankController();
    System.out.println(questionBankController.createPaper("花花", "1000001921032"));
    System.out.println(questionBankController.createPaper("豆豆", "1000001921051"));
    System.out.println(questionBankController.createPaper("大宝", "1000001921987"));
}

结果:

考生:花花
考号:1000001921032
--------------------------------------------
一、选择题

第1题:JAVA所定义的版本中不包括
A:JAVA2 Card
B:JAVA2 HE
C:JAVA2 EE
D:JAVA2 ME
E:JAVA2 SE
答案:B

第2题:表达式(11+3*8)/4%3的值是
A:1
B:0
C:31
D:2
答案:D

第3题:以下()不是合法的标识符
A:void
B:de$f
C:STRING
D:x3x;
答案:A

第4题:下列说法正确的是
A:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
B:JAVA程序中可以有多个main方法
C:JAVA程序的main方法必须写在类里面
D:JAVA程序中类名必须与文件名一样
答案:C

第5题:变量命名规范说法正确的是
A:变量由字母、下划线、数字、$符号随意组成;
B:A和a在java中是同一个变量;
C:不同类型的变量,可以起相同的名字;
D:变量不能以数字作为开头;
答案:D

二、问答题

第1题:小红马和小黑马生的小马几条腿
答案:4条腿

第2题:什么床不能睡觉
答案:牙床

第3题:铁棒打头疼还是木棒打头疼
答案:头最疼

第4题:为什么好马不吃回头草
答案:后面的草没了


考生:豆豆
考号:1000001921051
--------------------------------------------
一、选择题

第1题:下列说法正确的是
A:JAVA程序中可以有多个main方法
B:JAVA程序的main方法必须写在类里面
C:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
D:JAVA程序中类名必须与文件名一样
答案:B

第2题:表达式(11+3*8)/4%3的值是
A:2
B:1
C:31
D:0
答案:A

第3题:以下()不是合法的标识符
A:void
B:de$f
C:x3x;
D:STRING
答案:A

第4题:JAVA所定义的版本中不包括
A:JAVA2 Card
B:JAVA2 HE
C:JAVA2 ME
D:JAVA2 EE
E:JAVA2 SE
答案:B

第5题:变量命名规范说法正确的是
A:变量不能以数字作为开头;
B:A和a在java中是同一个变量;
C:不同类型的变量,可以起相同的名字;
D:变量由字母、下划线、数字、$符号随意组成;
答案:A

二、问答题

第1题:什么床不能睡觉
答案:牙床

第2题:铁棒打头疼还是木棒打头疼
答案:头最疼

第3题:为什么好马不吃回头草
答案:后面的草没了

第4题:小红马和小黑马生的小马几条腿
答案:4条腿


考生:大宝
考号:1000001921987
--------------------------------------------
一、选择题

第1题:以下()不是合法的标识符
A:x3x;
B:de$f
C:void
D:STRING
答案:C

第2题:表达式(11+3*8)/4%3的值是
A:31
B:0
C:2
D:1
答案:C

第3题:变量命名规范说法正确的是
A:不同类型的变量,可以起相同的名字;
B:变量由字母、下划线、数字、$符号随意组成;
C:变量不能以数字作为开头;
D:A和a在java中是同一个变量;
答案:C

第4题:下列说法正确的是
A:JAVA程序的main方法中如果只有一条语句,可以不用{}(大括号)括起来
B:JAVA程序的main方法必须写在类里面
C:JAVA程序中类名必须与文件名一样
D:JAVA程序中可以有多个main方法
答案:B

第5题:JAVA所定义的版本中不包括
A:JAVA2 EE
B:JAVA2 Card
C:JAVA2 HE
D:JAVA2 SE
E:JAVA2 ME
答案:C

二、问答题

第1题:为什么好马不吃回头草
答案:后面的草没了

第2题:小红马和小黑马生的小马几条腿
答案:4条腿

第3题:什么床不能睡觉
答案:牙床

第4题:铁棒打头疼还是木棒打头疼
答案:头最疼

Process finished with exit code 0

从以上的输出结果可以看到,每个人的题目和答案都是差异化的乱序的,如下图比对结果; - 花花、豆豆、大宝,每个人的试卷都存在着题目和选项的混乱排序

原型模式,乱序题目比对结果

七、总结

  • 以上的实际场景模拟了原型模式在开发中重构的作用,但是原型模式的使用频率确实不是很高。如果有一些特殊场景需要使用到,也可以按照此设计模式进行优化。
  • 另外原型设计模式的优点包括;便于通过克隆方式创建复杂对象、也可以避免重复做初始化操作、不需要与类中所属的其他类耦合等。但也有一些缺点如果对象中包括了循环引用的克隆,以及类中深度使用对象的克隆,都会使此模式变得异常麻烦。
  • 终究设计模式是一整套的思想,在不同的场景合理的运用可以提升整体的架构的质量。永远不要想着去硬凑设计模式,否则将会引起过渡设计,以及在承接业务反复变化的需求时造成浪费的开发和维护成本。
  • 初期是代码的优化,中期是设计模式的使用,后期是把控全局服务的搭建。不断的加强自己对全局能力的把控,也加深自己对细节的处理。可上可下才是一个程序员最佳处理方式,选取做合适的才是最好的选择。
Java编程23种设计模式实战篇1:目录 Java编程25种设计模式实战篇1:目录 Java编程25种设计模式实战篇2:Java设计模式之责任链一 Java编程25种设计模式实战篇3:Java设计模式_(行为型)_解析器模式 Java编程25种设计模式实战篇4:Java设计模式_(行为型)_访问者模式 Java编程25种设计模式实战篇5:Java设计模式_(行为型)_模版方法模式 Java编程25种设计模式实战篇6:Java设计模式_(行为型)_策略模式 Java编程25种设计模式实战篇7:Java设计模式_(行为型)_状态模式 Ja 阅读详情

相关推荐

设计模式之实战

在研究GoF设计模式基础上,结合笔者实战中的实际代码对各种23种设计模式进行了分析,说明每种模式的适用条件,与相关模式的关系,尽量避免用System.out去说明问题。

设计模式 (五) 设计模式实战系列

设计模式实战系列:介绍如何在实际项目中应用设计模式,包括如何选择合适的设计模式、如何实现设计模式、如何测试设计模式等。

Jackchen 的博客 1656

AlphaFold-multimer实战:从零开始预测STAT1-STAT2蛋白复合物结构

本文详细介绍了使用AlphaFold-multimer从零开始预测STAT1-STAT2蛋白复合物结构的完整实战流程。内容涵盖环境配置、数据库准备、序列处理、参数优化及结果可信度评估,为研究者利用这一AI工具进行复合物结构预测提供了系统指南和深度解析。

weixin_29094301的博客 885

原型模式及其实例

原型模式是23种设计模式中的创建型模式:创建型模式是设计模式中的一类,用于创建对象的方式和机制。它们提供了一种灵活的方式来实例化对象,同时隐藏了对象的创建细节,使代码更可维护、可扩展和可复用原型模式是一种创建型模式,通过复制现有对象来创建新对象。它提供了一种灵活、高效的对象创建方式,可以在需要大量相似对象的场景中提高性能和代码的可维护性。通过使用浅拷贝或深拷贝,原型模式可以灵活地克隆对象,使得新对象与原始对象相互独立。

a545__27的博客 415

SPAD单光子雪崩二极管:从基础原理到前沿应用

本文深入解析SPAD单光子雪崩二极管的基础原理、硬件实现关键及核心性能参数,并探讨其在激光雷达、量子通信和生物医学成像等前沿领域的创新应用。SPAD凭借超高灵敏度和精确的时间分辨率,正在推动自动驾驶、量子技术和医学诊断等领域的革命性发展。

weixin_30335575的博客 661

常见机械臂模型不用找!Mujoco这儿都有!

高质量的模型集合,franka panda,so-arm100,ur之类的机械臂都有。常见机械臂模型不用找!Mujoco这儿都有!大概346M,网速不行的可以下载zip。

darcsdn 992

设计模式面试题(总结最全面的面试题!!!)

文章目录设计模式什么是设计模式为什么要学习设计模式设计模式分类设计模式的六大原则开放封闭原则(Open Close Principle)里氏代换原则(Liskov Substitution Principle)依赖倒转原则(Dependence Inversion Principle)接口隔离原则(Interface Segregation Principle)迪米特法则(最少知道原则)(Deme...

小杰爱吃蛋的博客 6万+

从SD更新字库到FLASH,再用LCD显示

用Flash当字库存储载体。思路是先将要用到的字库文件存在SD卡,然后存储到Flash,LCD显示时候从Flash中读取 还挺顺利的,移植的原子的程序,自己稍加修改,主要是我的液晶屏函数,Flash读写函数,还有存储文件的flash地址不一样。一晚上搞定,大小字体都OK。挺高兴哈哈。这几天忙工作事情有点耽搁了学习进展嘿嘿 在text.c的showstr函数中char的字体颜色随意设置的,可以显...

weixin_30505751的博客 914

java编程之多线程实战指南(设计模式篇),从基础到避坑

多线程编程或者说范围更大的并发编程是一种非常复杂且容易出错的编程方式,但是我们为什么还要冒着风险艰辛地学习各种多线程编程技术、解决各种并发问题呢?因为并发是整个分布式集群的基础,通过分布式集群不仅可以大大降低同等负载能力的价格,还能使整体可扩展到的负载能力上限大大提升。低廉的服务成本使互联网行业的创意井喷,任何一个人都有能力创建并维持一个服务于成百上千甚至数万人的应用服务;而极高的服务能力上限让无数业务的线上化成为了可能,大大拓宽了互联网技术与业务的边界。在这个范围广大的并发技术领域当中多线程编程可以说是基

m0_57042151的博客 239

Type-C连接中的CC引脚:Rp与Rd电阻的识别与供电模式选择

本文深入解析Type-C接口中CC引脚的核心功能,包括Rp与Rd电阻的识别原理及供电模式选择机制。通过详细的分压计算和实战案例,揭示Type-C设备如何通过CC引脚实现方向检测、角色识别和供电协商,为硬件设计提供关键指导。

weixin_30616969的博客 340

SWC_RTE01-AutoSAR架构【AutoSAR架构设计概述】

1 基于AutoSAR架构的概述 1.1架构层面:功能可以细分子功能,各个子功能需要交互。 -大功能可以通过Autosar组件Composition去表示; -各个子功能一般具有不可分割性,可以通过Autosar原子组件Component去表示; -各个子功能的交互可以通过接口去通信和交互; -各个子功能的行为可以通过内部行为去表示;具体表现为Runnable的设计;架构设计的时候不考虑具体的逻辑实现;只会关注Ruannble的触发事件或周期;数据访问的一致性问题;具体逻辑设计可通过模版c文件实现或通过基于

8450

实战java设计模式(五)原型模式

目录1 介绍2 例子(实现Cloneable接口)2.1 课程类2.2 学生类2.3 测试主类3 反序列化方法3.1 课程类(可序列化即可)3.2 学生类4 总结 1 介绍 用于创建重复的对象,同时又能保证性能。说白了,就是解决对象的复制问题,希望通过Object.clone()直接返回一个复制的对象,注意!!是深拷贝。 2 例子(实现Cloneable接口) 用一个学生类来做实验,学生类里面组合了一个课程。 2.1 课程类 //课程类 class Course implements Cloneable {

你佳哥 203

RTCA DO-160G标准详解:航空电子设备的全面环境适应性测试指南

第二章的主要目的是提供标准中使用的术语和定义。了解这些术语对于准确理解标准的要求至关重要,特别是在技术实施过程中。RTCA DO-160G 涉及多个学科的知识,包括航空、电子、电磁学和机械工程,因此需要确保使用的术语在所有学科中具有一致的定义。为了确保测试人员和工程师在执行测试时对所有条件和要求的理解一致,RTCA DO-160G 标准中定义了大量术语。环境应力:指的是设备在操作过程中可能遇到的外部物理或化学条件,包括温度、湿度、振动等。电磁干扰(EMI)

qq_41854911的博客 5276

Java开发中的23种设计模式详解

Java开发中的23种设计模式详解

gfuugff的博客 6万+

光学测量仿真软件:OpticsBuilder_(9).热应力分析与补偿

在OpticsBuilder中,定义材料的热膨胀系数可以通过API进行。以下是一个Python代码示例,展示如何在OpticsBuilder中定义材料的热膨胀系数。

kkchenjj的博客 1085

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【JAVA长虹键法】第六式 原型模式(23种设计模式)

23种设计模式之原型模式

4万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

23种设计模式之原型模式(Prototype Pattern)

本篇文章将23种设计模式中的单例设计模式,此篇文章为一天学习一个设计模式系列文章,后面会分享其他模式知识。

小威的博客 2万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

瑞_23种设计模式_原型模式

本文章为瑞_系列专栏之《23种设计模式》的原型模式篇。原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。

阿瑞——从事Java后端,喜欢研读源码、自研框架、分享经验 2212

Java设计模式-创建型设计模式-原型模式

Java设计模式-创建型设计模式-原型模式

Fatter$hday的博客 1576

全面解读Java的23种设计模式

需要注意的是,混合使用设计模式要谨慎,不要过度使用设计模式,以免代码过于复杂和难以维护。选择合适的设计模式和合适的组合方式,可以使代码更加简洁、高效和易于维护。

weixin_39158966的博客 3265

Java 23 种设计模式:从踩坑到精通 —— 开篇及系列介绍

摘要:本文是《Java 23种设计模式:从踩坑到精通》系列的总入口与导航页。文章梳理了设计模式的起源与三大分类,结合SOLID六大原则,详解为什么2026年设计模式依然重要。提供25篇完整目录、面试高频Top10速记、场景速查索引、易混模式对比表及分级阅读路线,可作为长期收藏的设计模式学习手册。

折哥|智能物流与Java实战,副高数据库工程师。深耕出版社物流WMS/OMS(线体/立库/VGA),也分享Java进阶与OMS电商对接。Oracle→PG实战派。相信沉淀可迁移能力,分享通用技术,不藏不虚。 3554

硬肝系列:23种设计模式之原型模式

用示例代码来帮你了解原型模式 对于“设计模式”这个词大家肯定都不陌生,很多框架也用到了设计模式,但是大部分的开发者应该是没有深入的了解过,我准备硬肝下这23设计模式作为专题文章的开端,一共23种设计模式,我尽量在<23天肝完。 为什么要学习设计模式:https://blog.youkuaiyun.com/kaituozhe_sh/article/details/107922339 在我大学四年,对设计模式也没有什么概念,写代码就想着能实现就可以了,不会有设计模式那样的思想,但是当学习到了框架的时候,对于设计模式才

ALiangXLogic的博客 310

《23种设计模式(Java版)》| 原型模式(内附源码案例)。

## 一、概述 原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建——==来源于百度百科==。 `通俗理解:` - 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。 - 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的

我这么骄傲的一个人。 874

Java23种设计模式(二):原型模式

Java中的23种设计模式详解:本文介绍了GoF定义的23种经典设计模式,重点解析了原型模式(Prototype Pattern)。原型模式通过复制现有对象来创建新对象,避免了复杂初始化过程,提供三种实现方式:1) Cloneable接口实现浅拷贝;2) 序列化实现深拷贝;3) 手动复制实现定制拷贝。文中详细比较了各实现方式的优缺点,并提供了完整的Java示例代码,帮助开发者根据对象复杂度、性能需求等选择合适实现方案。原型模式特别适用于创建成本高的对象或需要动态配置的场景,能有效提高对象创建效率并降低系统耦

Regetless的博客 790

JAVA的23种设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

“ 春风若有怜花意,能否许我再少年。” 1132

Java常见的23种设计模式

大家好,我是钢板兽! 本文将系统梳理 Java 的设计模式,涵盖创建型、结构型和行为型三大类,结合定义、原理、优点、应用场景、示例代码,帮助你初步了解常见的23种设计模式。

weixin_49426115的博客 2481
上一篇: Java 23种设计模式系列之——实战建造者模式
下一篇: Java 23种设计模式系列之——实战单例模式
Java斗帝之路
博客等级 码龄7年 2392粉丝 687原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值