设计模式(一)-创建型之原型模式
2020/7/27 8:03:41
本文主要是介绍设计模式(一)-创建型之原型模式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
定义
- 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新对象
- 不需要知道任何创建细节,不调用构造函数
适用场景
- 创建对象麻烦或困难时。1.对象种类繁多,无法整合到一个类时 2.要创建一个类,初始化时需要使用较多资源。
- 想解耦框架和生成实例时,生成的框架不依赖于具体的类。
优点
- 创建过程简单
- 原型模式性能比直接new一个对象性能高
缺点
- 必须配备克隆方法
- 对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入代码BUG
- 必须清楚了解深拷贝与浅拷贝
原型模式中的角色
角色说明
-
Prototype(原型)
- Product角色负责定义用于复制现有实例来生成新实例的方法。在实例程序中,由
Cloneable
接口来扮演此角色。
- Product角色负责定义用于复制现有实例来生成新实例的方法。在实例程序中,由
-
ConcreteProrotype(具体原型)
- ConcretePrototype角色负责实现复制现有实例并生成新实例方法。在实例程序中,由
User
类扮演此角色。
- ConcretePrototype角色负责实现复制现有实例并生成新实例方法。在实例程序中,由
-
Client(使用者)
- Client角色负责使用复制实例的方法生成新的实例。在实例程序中,由单元测试类扮演此角色。
类图
代码实现
原型模式代码
写法一
1.用java实现原型模式比较简单,只需要将目标类实现Cloneable
接口即可
@Getter @Setter @AllArgsConstructor public class User implements Cloneable { private String name; private Date birthday; public User() { System.out.println("User constructor被调用"); } @Override public Object clone() throws CloneNotSupportedException { System.out.println("User clone被调用"); // 浅克隆写法 return super.clone(); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", birthday=" + birthday + '}'+super.toString(); } }
写法二
- 抽象父类实现Cloneable接口
public abstract class AbstractUser implements Cloneable { @Override protected Object clone() throws CloneNotSupportedException { System.out.println("抽象父类clone方法被调用"); return super.clone(); } }
- 目标类继承抽象父类接口
@Getter @Setter public class User extends AbstractUser { private String name; private Date birthday; public User() { System.out.println("User constructor被调用"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", birthday=" + birthday + '}'+super.toString(); } }
单元测试(写法一)
测试代码
@Test public void testClone() throws CloneNotSupportedException { Date birthday = new Date(0L); // 1. 创建用户对象 User user1 = new User(); user1.setName("小林"); user1.setBirthday(birthday); // 2. 克隆用户对象 User user2 = (User) user1.clone(); // 3. user1,user2对比 System.out.println(user1); System.out.println(user2); System.out.println(user1 == user2); System.out.println("<==============我是分割线============>"); // 4. 赋值新的birthday并打印 user1.getBirthday().setTime(666666666666L); System.out.println(user1); System.out.println(user2); System.out.println(user1 == user2); }
执行结果
根据user1和user2的hash值不同可以看出是不同的类,但user1的birthday修改后,user2的birthday也同样被修改,说明user1和user2指向了同一个birthday,这里就引发深拷贝与浅拷贝的问题。
深拷贝 VS 浅拷贝
使用clone()
,之后,由于birthday
是一个引用对象,由于是浅拷贝,user中的引用成员变量依然指向的是同一个。
什么是深拷贝,我们clone
user对象的同时,也将其内部引用的对象进行拷贝,使得每个引用对象无关联,都是单独的对象。
深拷贝代码改造
重新改造user中clone()
方法的实现
@Getter @Setter public class User implements Cloneable { private String name; private Date birthday; public User() { System.out.println("User constructor被调用"); } @Override public Object clone() throws CloneNotSupportedException { System.out.println("User clone被调用"); // 浅拷贝写法 // return super.clone(); // 深拷贝写法 User user = (User) super.clone(); user.birthday=(Date) user.getBirthday().clone(); return user; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", birthday=" + birthday + '}'+super.toString(); } }
执行结果
可以看到改造完成之后user1的birthday与user2的birthday指向不是同一个birthday了。
总结
使用原型模式时要十分注意深拷贝、浅拷贝的问题,即使了解了深拷贝和浅拷贝,在写代码的过程中一个疏忽就可能产生BUG,如果对深拷贝和浅拷贝不了解同学,需要慎用原型模式。
这篇关于设计模式(一)-创建型之原型模式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-06小米11i印度快充版ROM合集:极致体验,超越期待
- 2024-10-06【ROM下载】小米11i 5G 印度版系统, 疾速跃迁,定义新速度
- 2024-10-06【ROM下载】小米 11 青春活力版,青春无极限,活力全开
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 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 实现数据请求