Java设计模式之创建型-原型模式(UML类图+案例分析)

news/2025/1/15 22:55:23/

目录

一、基础概念

二、UML类图

三、角色设计

四、案例分析 

1、通用实现(浅克隆)

2、深克隆

五、总结


一、基础概念

通过复制已有对象作为原型,通过复制该原型来返回一个新对象,而不是新建对象,说白了就是不断复制相同的对象罢了。

二、UML类图

三、角色设计

角色描述
抽象原型类规定了具体的原型对象必须实现的clone()方法
具体原型类实现抽象原型类的clone()方法,它是可以为复制的对象
访问类使用具体原型类中的clone()方法来复制新的对象

四、案例分析 

1、通用实现(浅克隆)

定义一个学生类,实现Cloneable接口并重写clone方法。

super.clone()是基于对象在内存中的二进制位面值进行复制的一种浅拷贝实现。它的优点是效率高,不需要进行逐字段复制,因此不会调用对象的构造函数,也就是不需要经历初始化的过程。

    @Overrideprotected Student clone(){Student student = null;try {student = (Student) super.clone();}catch (Exception e){e.printStackTrace();}return student;}

其内部属性有name和Teacher类,实现有参构造,get和set方法,重写toString()方法。 

public class Student implements Cloneable{private String name;@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", teacher=" + teacher +'}';}private Teacher teacher;public Student(String name, Teacher teacher) {this.name = name;this.teacher = teacher;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Teacher getTeacher() {return teacher;}public void setTeacher(Teacher teacher) {this.teacher = teacher;}@Overrideprotected Student clone(){Student student = null;try {student = (Student) super.clone();}catch (Exception e){e.printStackTrace();}return student;}
}

写一个主方法测试:

    public static void main(String[] args) {Teacher teacher = new Teacher("赵老师");Student student = new Student("李四",teacher);Student clone = student.clone();clone.getTeacher().setName("老王老师");System.out.println(student);System.out.println(clone);}

运行结果如下:

运行完毕以后会发现一个问题,就是我克隆出来的学生换了新的老王老师以后,怎么原来学生对象的老师也变成了老王老师,这明显不对呀!

从运行的结果上分析,应该是teacher共用同一个内存地址,意味着复制的不是值,而是引用的地址,这正是浅拷贝的特征:

1、对基本数据类型进行值复制

2、对引用类型仅复制引用,没有复制引用的对象

解决办法是在clone时,需要深拷贝teacher对象,断开student和clone的teacher对象引用关系,使两者独立。

2、深克隆

Student类需要实现Serializable接口,并自定义了deepClone方法实现深克隆,每一行代码解释如下:

1、创建字节数组输出流,用于存放序列化后的二进制数据。

ByteArrayOutputStream bos = new ByteArrayOutputStream();

2、 基于字节数组输出流创建对象输出流,用于序列化对象。

ObjectOutputStream oos = new ObjectOutputStream(bos);

3、 将当前对象写入对象输出流进行序列化,序列化后的二进制数据存入字节数组输出流。

oos.writeObject(this);

4、获取字节数组输出流中的数据(序列化后的二进制数据),封装为字节数组输入流。

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

5、基于字节数组输入流创建对象输入流,用于反序列化对象。

ObjectInputStream ois = new ObjectInputStream(bis);

6、从对象输入流中读取流数据并反序列化生成对象,返回反序列化得到的学生对象副本。

return (Student) ois.readObject();

完整的关键代码如下: 

public class Student implements Cloneable, Serializable {//构造、get和set方法、toString()方法省略public Student deepClone(){try{ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (Student) ois.readObject();}catch (Exception e){e.printStackTrace();return null;}}}

总结起来,这段代码使用了序列化和反序列化来实现对象的深克隆,核心思路是将对象写入流,然后从流里再读出来克隆对象。 

同时Teacher类也需要实现Serializable序列化接口,关键代码如下:

public class Teacher implements Serializable {}

但不需要实现深克隆,原因如下:

在通过序列化实现Student深克隆时,会自动将Student对象所引用的Teacher对象全部序列化,并在反序列化时重新创建出一个新的Teacher对象。

Teacher对象已经在这个序列化/反序列化的过程中被自动深克隆了,不需要再单独实现深克隆方法。

主方法测试:

    public static void main(String[] args) {Teacher teacher = new Teacher("赵老师");Student student = new Student("李四",teacher);Student clone = student.deepClone();clone.getTeacher().setName("老王老师");System.out.println(student);System.out.println(clone);}

运行结果如下: 

五、总结

优点:

避免重复创建成本高的对象。

客户端可以直接获得对象副本,不需要知道如何创建。

可以动态添加或者修改复制逻辑。

缺点:

需要为每一个类配置一个克隆方法。

复制对象的成本也存在,特别是深拷贝。

需要注意隔离对象状态,避免相互影响。

应用场景:

对象的创建成本比较大,可以通过复制原型对象避免重复创建。

需要重复创建相似对象时可以考虑原型模式。

需要避免使用子类式继承改变对象结构时。

符合的原则:

1、开闭原则(Open Closed Principle)

原型模式通过克隆生成新对象,而不需要修改源对象的类,对扩展开放,对修改关闭。

2、组合复用原则(Composite Reuse Principle)

原型模式复用的是对象,不需要通过继承创建子类,可以更灵活地复用对象。

3、单一职责原则(Single Responsibility Principle)

原型类只需要实现Cloneable接口,不需要其他责任,专注于复制自己。

4、里氏替换原则(Liskov Substitution Principle)

原型模式生成的对象和原对象是一致的,扩展也不会破坏原有系统。

5、依赖倒转原则(Dependency Inversion Principle)

客户端只依赖于原型类的接口,不依赖具体实现,降低了依赖。

原型模式通过对象复制获取实例,避免重复创建开销大的对象,是一种快速获取对象副本的模式,但需要注意副本状态的一致性管理。


http://www.ppmy.cn/news/834248.html

相关文章

源启:云原生计算架构的行业实现

7月5日,由工业和信息化部网络安全产业发展中心、中国软件行业协会等单位指导,中国电子主办的“麒麟傲天聚创未来2023操作系统产业大会”在京举行。中电金信研究院副院长陈书华在大会上发表主旨演讲。 陈书华认为数字经济已成为社会发展的重要引擎&#…

a链接分享到facebook、twitter 如何写

//这是facebook <a href"https://www.facebook.com/sharer/sharer.php?uhttp://huayuncc.com/index.html" target"_blank" classicon ><img src"imgs/facebook-icon.png" alt""></a> //这是twitter <a href…

微软、Google、Twitter、Facebook登录

文章目录 微软、Google、Twitter、Facebook登录1.背景2.微软登录(1&#xff09;官方文档地址&#xff08;2&#xff09;时序图a、步骤10b、步骤12 3、谷歌登录&#xff08;1&#xff09;官方文档地址&#xff08;2&#xff09;时序图&#xff08;3&#xff09;步骤说明步骤7 5、…

如何运营推特营销主账号

在推特上做产品推广&#xff0c;Twitter群&#xff08;发&#xff09;推王建议&#xff1a;一般需要两类账号。 主账号&#xff1a;也就是官方号&#xff0c;用来聚集粉丝&#xff0c;日常产品信息、新闻资讯发布的&#xff1b; 批量推广号&#xff1a;也叫小号或者广告号&am…

Twitter(一)

Twitter的核心业务逻辑&#xff0c;在于Following和Be followed。[5] 进入Twitter个人主页&#xff0c;你会看到你following的那些作者&#xff0c;最近发表的微博客。所谓微博客&#xff0c;就是一则短信&#xff0c;Twitter规定&#xff0c;短信的长度不得超过140个字。短信不…

一个大神的twitter

今天看见一个大神的twitter&#xff0c;居然能够拿到微软win10各种版本的update ISO&#xff0c;还能拿到微软各种最新软件的release和preview版本&#xff0c;是黑客还是内鬼。 twitter的地址&#xff1a; https://twitter.com/WZorNET 下面是他的一些最新的twitter文链接&…

分享链接内容到Facebook和twitter

使用<a href""></a>分享链接的好处是&#xff0c;不需要第三方的依赖&#xff0c;只要客户端能访问Facebook和twitter即可(使用VPN) 1. 分享链接到Facebook的写法 <a href"https://www.facebook.com/sharer.php?u${shareUrl}" target&q…

Twitter分享集成

1.Twitter账号登录 https://developer.twitter.com/en.html 2.申请账号升级为开发者 https://developer.twitter.com/en/verify 此过程需要几天时间&#xff0c;申请通过后会有邮件验证 3.添加app https://developer.twitter.com/en/apps/create 添加完会有appkey和secre…