尚硅谷设计模式学习--- [原型模式(Prototype模式),深拷贝与浅拷贝]
Posted 小智RE0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了尚硅谷设计模式学习--- [原型模式(Prototype模式),深拷贝与浅拷贝]相关的知识,希望对你有一定的参考价值。
🚀🚀🚀尚硅谷传送门==>B站尚硅谷Java设计模式
❤❤❤感谢尚硅谷❤❤❤
🛴🛴🛴最近开始计划学习一下设计模式了,加油!!!
原型模式
由克隆羊问题分析原型模式
现在有一只羊tom,姓名为: tom, 年龄为:1,颜色为:白色,请编写程序创建和tom
羊 属性完全相同的10只羊。
传统思路;直接new一个羊的对象; 拿过来依赖(使用)即可;
后面向"克隆这只羊",直接把姓名,年龄,属性全部复用.
传统思路代码;
羊Sheep
//羊';
public class Sheep {
//定义羊的属性;
private String name;
private String color;
private int age;
//构造方法初始化;
public Sheep(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\\'' +
", color='" + color + '\\'' +
", age=" + age +
'}';
}
}
客户端Client
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("小智", "白色", 21);
//克隆羊;
Sheep sheep1=new Sheep(sheep.getName(),sheep.getColor(),sheep.getAge());
Sheep sheep2=new Sheep(sheep.getName(),sheep.getColor(),sheep.getAge());
Sheep sheep3=new Sheep(sheep.getName(),sheep.getColor(),sheep.getAge());
Sheep sheep4=new Sheep(sheep.getName(),sheep.getColor(),sheep.getAge());
Sheep sheep5=new Sheep(sheep.getName(),sheep.getColor(),sheep.getAge());
Sheep sheep6=new Sheep(sheep.getName(),sheep.getColor(),sheep.getAge());
//被克隆的羊;
System.out.println(sheep);//Sheep{name='小智', color='白色', age=21}
//克隆羊;
System.out.println(sheep1);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep2);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep3);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep4);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep5);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep6);//Sheep{name='小智', color='白色', age=21}
}
}
这种方式简单明了,可读性很高;
但是创建新的对象之前,就得去重新获取原始对象的属性,要是属性特别多的时候(甚至有其他类作为属性的情况),这样"克隆"的效率就比较低了
原型模式引入
Object类提供了一个clone()方法,该方法将一个Java对象复制一份,但需要实现clone的Java类必须要实现接口Cloneable
(该接口表示该类能够复制且具有复制的能力),
用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
用原型模式优化;
羊Sheep
//羊'; 实现 Cloneable 接口;==>该接口表示该类能够复制且具有复制的能力;
public class Sheep implements Cloneable{
//定义羊的属性;
private String name;
private String color;
private int age;
//构造方法初始化;
public Sheep(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\\'' +
", color='" + color + '\\'' +
", age=" + age +
'}';
}
//克隆方法;
@Override
protected Object clone(){
//别忘了此处返回的是 羊
Sheep sheep=null;
try {
sheep=(Sheep)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return sheep;
}
}
客户端Client
//客户端;
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("小智", "白色", 21);
//克隆羊;
Sheep sheep1 = (Sheep)sheep.clone();
Sheep sheep2 = (Sheep)sheep.clone();
Sheep sheep3 = (Sheep)sheep.clone();
Sheep sheep4 = (Sheep)sheep.clone();
Sheep sheep5 = (Sheep)sheep.clone();
//被克隆的羊;
System.out.println(sheep);//Sheep{name='小智', color='白色', age=21}
//克隆羊;
System.out.println(sheep1);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep2);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep3);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep4);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep5);//Sheep{name='小智', color='白色', age=21}
}
}
原型模式的缺点
:由于原型模式需要为每一个类配备一个克隆方法,如果说要对已有的类进行改造时,需要修改其源代码,违背了ocp原则(开闭原则).
在spring工作时,也使用到了原型模式
例如,写个实体类
//用户实体类;
public class User {
private String name;
private String password;
private int age;
public User() {
}
public User(String name, String password, int age) {
this.name = name;
this.password = password;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\\'' +
", password='" + password + '\\'' +
", age=" + age +
'}';
}
}
配置,让该类注入使用spring
作用类型(影响) 切换为scope=“prototype”;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 使用原型模式 ,scope="prototype" -->
<bean id="user" class="com.lzq.pojo.User" scope="prototype">
<property name="name" value="小智"/>
<property name="password" value="123654"/>
<property name="age" value="21"/>
</bean>
</beans>
测试
public class PrototypeTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
Object user1 = applicationContext.getBean("user");
System.out.println(user1);//User{name='小智', password='123654', age=21}
Object user2 = applicationContext.getBean("user");
System.out.println(user2);//User{name='小智', password='123654', age=21}
//可以注意到,取到的两个对象不一样;
System.out.println(user1 == user2); //user
}
}
debug调试调试
浅拷贝
就用刚才克隆羊案例来看;
这只羊有个好朋友;
在原来的基础上添加一个Sheep类型的属性;
//羊'; 实现 Cloneable 接口;==>该接口表示该类能够复制且具有复制的能力;
public class Sheep implements Cloneable{
//定义羊的属性;
private String name;
private String color;
private int age;
//这只羊有个好朋友;
public Sheep friend;
//构造方法初始化;
public Sheep(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\\'' +
", color='" + color + '\\'' +
", age=" + age +
'}';
}
//克隆方法;
@Override
protected Object clone(){
//别忘了此处返回的是 羊
Sheep sheep=null;
try {
sheep=(Sheep)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return sheep;
}
}
然后客户再去"克隆"
//客户端;
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("小智", "白色", 21);
//这只羊的好朋友;
sheep.friend=new Sheep("帕克","白色",12);
//克隆羊;
Sheep sheep1 = (Sheep)sheep.clone();
Sheep sheep2 = (Sheep)sheep.clone();
//被克隆的羊;
System.out.println(sheep);//Sheep{name='小智', color='白色', age=21}
//克隆羊;
System.out.println(sheep2);//Sheep{name='小智', color='白色', age=21}
System.out.println(sheep2);//Sheep{name='小智', color='白色', age=21}
//克隆后的好朋友;
System.out.println("克隆后的好朋友"+sheep1.friend.hashCode());//克隆后的好朋友1554874502
System.out.println("克隆后的好朋友"+sheep2.friend.hashCode());//克隆后的好朋友1554874502
}
}
注意到克隆羊的好朋友也没有变;
通俗地说浅拷贝;
比如说在对象A中,有个属性W, 这个属性W它是指向 对象B的;
这时 对象 A 被克隆了;但是属性W 还是指向 对象B的
;并不是说把对象B克隆一份,然后指向.
浅拷贝默认使用 clone( )
方法实现
- 数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
- 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递(
注意;Java只有值传递
),也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。注意;在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
;因为他们指向的地址是同一个.
深拷贝
- 复制对象的所有基本数据类型的成员变量值
- 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象最终指向的的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝.
在刚才的例子中,要是用深拷贝,那么对象B的也要复制一份.
深拷贝有两种实现方式
实现深拷贝之 重写clone方法
写个User
类
作为另一个类的引用类型属性;
注意user类
public class User implements Cloneable {
private String name;
private String address;
//构造方法;
public User(String name, String address) {
this.name = name;
this.address = address;
}
//克隆方法;
@Override
protected Object clone() 尚硅谷设计模式学习---[装饰者模式]
尚硅谷设计模式学习(23)---[策略模式(strategy pattern)]