设计模式---原型模式

本文介绍了原型模式在创建复杂对象时的优势,通过一个四六级考试试卷乱序生成的例子,展示了如何利用Java实现原型模式。在考试系统中,每个考生的试卷需要随机排列,原型模式结合工厂方法用于快速复制并修改试卷,避免了重复的初始化操作。同时,文章提到了原型模式在实际项目中可能存在的挑战,并强调设计模式应服务于实际需求。
摘要由CSDN通过智能技术生成

原型模式

原型模式的主要作用就是创建对象,我们需要创建的对象可能是来自数据库,也可能是通过RPC接口来获取,这样我们可以通过克隆来获取对象以节省时间。

原型模式在程序应用中很少,并不像工厂、建造者、代理模式用的那么广泛,但是在我们生活中,例如:自身细胞的有丝分裂,再者工作中Ctrl + C 加上 Ctrl + V 的你,这些都是原型模式。

什么时候用原型模式?例如类初始化消耗资源时,再比如创建对象很麻烦时,总之当创建对象的效率很低的时候,可以考虑使用原型模式。

在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。

比如我们在四六级考试的时候,每个人都是不一样的试卷,在同一考场的同学,即使听力的部分是一样的,但是每个选项的顺序也是不一样的。我们可以通过模拟考试,通过相同的题库,但是打乱题目顺序和选项来实现原型模式。

原型模式解决的就是创建大量重复的类,最长用的手段就是克隆,在每个需要克隆的都需要实现Cloneable接口。

插曲:在JavaScript中每个对象都有自己的原型,最高的原型就是Object,每个被继承的原型可以把自己的属性传给下一代,有兴趣的可以了解下,类似于Java中的继承。

模拟上机试卷实现原型模式

试卷选择题

public class ChoiceQuestion {
 private String name; // 题⽬
 private Map<String, String> option; // 选项
 private String key; // 答案
 public ChoiceQuestion() {
 }
 
 public ChoiceQuestion(String name, Map<String, String> option, String key) {
 this.name = name;
 this.option = option;
 this.key = key;
 }
 // 此处省略get set
}

试卷问答题

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
}

试卷随机排序工具类

/**
* 乱序Map元素,记录对应答案key
* @param option 题⽬
* @param key 答案
* @return Topic 乱序后的答案
*/
 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 index = 0;
 	String keyNew = "";
 	for (String next : keySet) {
 	String randomKey = keyList.get(index++);
 
 		if (key.equals(next)) {
 			keyNew = randomKey;
 		}
 		
 	optionNew.put(randomKey, option.get(next));
 	}
 	//返回乱序后答案对应的map
 return new Topic(optionNew, keyNew);
}

试卷类

package PrototypePattern;

/**
 * @Author: jerrold chen
 * @Date: 2021/03/31
 * @Version 1.0
 * @description:
 */
public class Question implements Cloneable {
    private String name; // 姓名
    private String id; // 考号
    
    private ArrayList<ChoiceQuestion> choiceQuestionList = new
            ArrayList<ChoiceQuestion>();
    private ArrayList<AnswerQuestion> answerQuestionList = new
            ArrayList<AnswerQuestion>();

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

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

    @Override
    public Object clone() throws CloneNotSupportedException {
        Question question = (QuestionBank) super.clone();
        Question.choiceQuestionList = (ArrayList<ChoiceQuestion>)
                choiceQuestionList.clone();
        Question.answerQuestionList = (ArrayList<AnswerQuestion>)
                answerQuestionList.clone();
        // 题⽬乱序
        Collections.shuffle(question.choiceQuestionList);
        Collections.shuffle(question.answerQuestionList);
        // 答案乱序
        ArrayList<ChoiceQuestion> choiceQuestionList = question.choiceQuestionList;
        for (ChoiceQuestion questions : choiceQuestionList) {
            Topic random = TopicRandomUtil.random(questions.getOption(),
                    questions.getKey());
            questions.setOption(random.getOption());
            questions.setKey(random.getKey());
        }
        return question;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        StringBuilder detail = new StringBuilder("考⽣:" + name +
                "\r\n" +
                "考号:" + id + "\r\n" +
                "--------------------------------------------\r\n" +
                "⼀、选择题" + "\r\n\n");
        for (int i= 0; i < choiceQuestionList.size(); i++) {
            detail.append("第").append(i +
                    1).append("题:").append(choiceQuestionList.get(i).getName()).append("\r\
                    n");
                    Map < String, String > option =
                            choiceQuestionList.get(i).getOption();
            for (String key : option.keySet()) {

                detail.append(key).append(":").append(option.get(key)).append("\r\n");
                ;
            }
            detail.append("答案:").append(choiceQuestionList.get(i).getKey()).append("\r\n\n");
        }
        detail.append("⼆、问答题" + "\r\n\n");
        for (int i = 0; i < answerQuestionList.size(); i++) {
            detail.append("第").append(i +
                    1).append("题:").append(answerQuestionList.get(i).getName()).append("\r\n");
                    detail.append("答案:").append(answerQuestionList.get(i).getKey()).append("\r\n\n");
        }
        return detail.toString();
    }
}

考试初始化试卷

public class QuestionHander{
	private Question question = new Question();
	
	public QuestionHander(){
	Map<String, String> map1 = new HashMap<String, String>();
        map1 .put("A", "JAVA");
        map1 .put("B", "C++");
        map1 .put("C", "Golang");
        map1 .put("D", "TypeScript");
    Map<String, String> map2= new HashMap<String, String>();
        map2.put("A", "封装");
        map2.put("B", "继承");
        map2.put("C", "多态");
        map2.put("D", "妈卖批");
	}
	question.append(new ChoiceQuestion("以下哪种语言最牛逼",map1,"A"))
			.append(new ChoiceQuestion("以下哪个是Java没有的特性",map1,"D"))
			.append(new AnswerQuestion("一斤棉花和一斤铁那个重","一样重"))
			.append(new AnswerQuestion("请用四个数字阵形容厂长","4396"));		
//此处省略多题。。。。

public String create(String id, String name) throwsCloneNotSupportedException {

 	Question questionClone = (Question)question.clone();
	questionClone.setCandidate(name);
 	questionClone.setNumber(id);
 	return questionClone.toString();
 }

测试

@Test
public void test() throws CloneNotSupportedException {
 	QuestionHander questionHander= new QuestionHander();
 	System.out.println(QuestionHander .createPaper("clearlove","001"));
 	System.out.println(QuestionHander .createPaper("UZI","002"));
 	System.out.println(QuestionHander .createPaper("Looper","003"));
}

总结:原型模式实际中用到的情况相对较少,但是它的优点在于便于通过克隆⽅式创建复杂对象、也可以避免重复做初始化操作、不需要与类中所属的其他类耦合等。但也有⼀些缺点如果对象中包括了循环引⽤的克隆,以及类中深度使⽤对象的克隆,都会使此模式变得异常麻烦。总之设计模式只是一种思想,切莫为了设计模式而设计模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值