设计模式——创建类——原型模式
2021/5/18 10:57:26
本文主要是介绍设计模式——创建类——原型模式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、原型模式
Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 对象.clone()
-
性能优良,原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
-
逃避构造函数的约束,这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。
-
创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
-
不用重新初始化对象,而是动态地获得对象运行时的状态
-
如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
-
在实现深克隆的时候可能需要比较复杂的代码
-
需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则,这点请同学们注意.
二、代码
模拟一个发放工资短信通知的例子:
SalaryTemplate.java
@Data public class SalaryTemplate { private String salSubject="工资发放通知"; private String salContext="本月工资已发放,请您注意查收!"; }
Mail.java
@Data public class Mail implements Cloneable { private String username; private String subject; private String context; private String tail; public Mail(SalaryTemplate salaryTemplate) { this.subject = salaryTemplate.getSalSubject(); this.context = salaryTemplate.getSalContext(); } @Override public Mail clone() { Mail mail = null; try { mail = (Mail) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); System.out.println(e.getMessage()); } return mail; } }
mail实现了cloneable接口,在类中重写了clone()方法。
Client.java
public class Client { private static final int STR_LEN = 6; public static void main(String[] args) { Mail mail = new Mail(new SalaryTemplate()); mail.setTail("感谢您对我们工作的支持"); int i = 0; while (i < 6) { Mail cloneMail = mail.clone(); cloneMail.setUsername(getRandomString(STR_LEN)); sendMail(cloneMail); i++; } } private static void sendMail(Mail cloneMail) { System.out.println("通知主题:" + cloneMail.getSubject() + " 通知内容: " + "尊敬的" + cloneMail.getUsername() + ", " + cloneMail.getContext() + cloneMail.getTail()); } private static String getRandomString(int length) { String source = "abcdefghijklmnopqrskuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; StringBuffer sb = new StringBuffer(); Random rand = new Random(); for (int i = 0; i < length; i++) { sb.append(source.charAt(rand.nextInt(source.length()))); } return sb.toString(); } }
三、浅拷贝与深拷贝
Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。
内部的数组和引用对象才不拷贝,其他的原始类型比如int、long、char等都会被拷贝,但是对于String类型,Java就希望你把它认为是基本类型,它是没有clone方法的,处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串,在使用的时候就把String当做基本类使用即可。
使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。
实现深拷贝的两种方式:
方式一:使用clone方法:
@Data public class Thing implements Cloneable { private String name; private ArrayList<String> stringList; @Override public Thing clone() { Thing cloneThing = null; try { cloneThing = (Thing) super.clone(); cloneThing.stringList = (ArrayList<String>) this.stringList.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return cloneThing; } }
方式二:使用序列化(推荐)
@Data class SerialClone implements Cloneable, Serializable { private String name; private ArrayList<String> strings; @Override public Object clone() throws CloneNotSupportedException { try { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) { objectOutputStream.writeObject(this); } try (InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) { ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); return objectInputStream.readObject(); } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); return null; } } public static void main(String[] args) throws CloneNotSupportedException { SerialClone serialClone=new SerialClone(); ArrayList<String> arrayList=new ArrayList<>(2); arrayList.add("java"); serialClone.setName("Clone"); serialClone.setStrings(arrayList); System.out.println(serialClone.getStrings()); SerialClone clone= (SerialClone) serialClone.clone(); clone.getStrings().add("vue"); System.out.println(clone.getStrings()); System.out.println(serialClone.getStrings()); System.out.println(serialClone==clone); } }
这篇关于设计模式——创建类——原型模式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求
- 2024-10-01使用 golang 将ETH账户的资产平均分散到其他账户
- 2024-10-01JWT用户校验课程:从入门到实践
- 2024-10-01Server Component课程入门指南
- 2024-09-30Dnd-Kit学习:新手快速入门指南