设计模式之原型模式

1 引子

在实际项目中,有时候会复制对象,具体可看下方代码。
可克隆的Person类:

public class Person implements Cloneable {
	private String name;
	private int age;
	private String sex;
	
	public Person(String name, int age, String sex){
		this.name = name;
		this.age = age;
		this.sex = sex;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}
	
	@Override
	public Object clone() throws CloneNotSupportedException{
		Object object = super.clone();
		return object;
	}
}

这里继承Cloneable接口,作用在于运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在JVM中,只有实现了Cloneable接口的类才可以被拷贝,否则运行抛CloneNotSupportedException异常。
同时,Object类自带clone(),但其作用域为protected,所以一般很难被调用,这里重写clone方法是为了扩大clone()方法的作用域。

客户端:

public class Client {
	public static void main(String[] args) {
		Person person1 = new Person("xiaoLi", 20, "m");
		Person person2 = null;
		try {
			person2 = (Person)person1.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		System.out.println(person1 + "    " + person2);
		person1.setName("xiaoMing");
		System.out.println(person1 + "    " + person2);
	}
}

运行结果

Person [name=xiaoLi, age=20, sex=m]    Person [name=xiaoLi, age=20, sex=m]
Person [name=xiaoMing, age=20, sex=m]    Person [name=xiaoLi, age=20, sex=m]

这种通过克隆原型对象获得另外一个对象的创建模式称为原型模式。

这里讲到对象克隆,就要区分浅拷贝和深拷贝:
先看个例子来说明下浅拷贝和深拷贝。

import java.util.ArrayList;
import java.util.List;
public class City implements Cloneable {
	private String name;
	private int area;
	private List<Person> persons;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getArea() {
		return area;
	}
	public void setArea(int area) {
		this.area = area;
	}
	public List<Person> getPersons() {
		return persons;
	}
	public void setPersons(List<Person> persons) {
		this.persons = persons;
	}
	@Override
	public String toString() {
		return "City [name=" + name + ", area=" + area + ", persons=" + persons
				+ "]";
	}
	
	public Object clone() throws CloneNotSupportedException {
		// 浅拷贝方式
		City city = (City)super.clone();
		
		// 深拷贝方式
//		List<Person> personNew = new ArrayList<Person>();
//		List<Person> persons = city.getPersons();
//		for (Person personTemp : persons) {
//			personNew.add((Person)personTemp.clone());
//		}
//		city.setPersons(personNew);
		return city;
	}
}
public class Client {
	public static void main(String[] args) {
		Person person1 = new Person("xiaoLi", 20, "m");
		Person person2 = new Person("xiaoZhao", 25, "f");
		Person person3 = new Person("xiaoQi", 30, "f");
		
		List<Person> persons = new ArrayList<Person>();
		persons.add(person1);
		persons.add(person2);
		persons.add(person3);
		
		City city = new City();
		city.setName("beijing");
		city.setArea(110);
		city.setPersons(persons);
		
		City city2 = null;
		try {
			city2 = (City)city.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		System.out.println(city);
System.out.println(city2);
		city.setName("nanjing");
		person1.setAge(100);
		System.out.println(city);
System.out.println(city2);
	}
}

浅拷贝运行结果:

City [name=beijing, area=110, persons=[Person [name=xiaoLi, age=20, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]
City [name=beijing, area=110, persons=[Person [name=xiaoLi, age=20, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]
=============================================================================
City [name=nanjing, area=110, persons=[Person [name=xiaoLi, age=100, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]
City [name=beijing, area=110, persons=[Person [name=xiaoLi, age=100, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]

深拷贝运行结果:

City [name=beijing, area=110, persons=[Person [name=xiaoLi, age=20, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]
City [name=beijing, area=110, persons=[Person [name=xiaoLi, age=20, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]
=============================================================================
City [name=nanjing, area=110, persons=[Person [name=xiaoLi, age=100, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]
City [name=beijing, area=110, persons=[Person [name=xiaoLi, age=20, sex=m], Person [name=xiaoZhao, age=25, sex=f], Person [name=xiaoQi, age=30, sex=f]]]

结果表明:
①浅拷贝对于对象内部的引用对象只会copy引用,其指向的地址与原型对象内引用对象指向的地址相同。
浅拷贝
如上图所示,修改persons列表中的任何一个person元素,都会影响原型对象和浅拷贝对象。对于技术基本数据类型和String类型,则不受任何影响。
②深拷贝对于原型对象中引用对象都会进行拷贝,从代码中也能看出。
深拷贝
因此对原型对象中引用对象的属性age进行修改,不会影响到深拷贝对象的值。对于浅拷贝和深拷贝可参考下方的参考资料。

2 原型模式原理

《大话设计模式》中定义原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。意思就是说:通过clone方式创建新对象就是原型模式。

3 原型模式特点

原型模式有什么优点?
通过clone方法创建新的对象,比直接new一个对象要快。因为克隆对象不需要经过构造方法,直接操作内存中的二进制流,免去了类的初始化工作。
原型模式有什么缺点?
实际原型模式用的并不多,因为涉及到浅拷贝和深拷贝。同时要避免与单例模式混用,因为clone()方法不会通过构造函数来创建对象,而单例模式之所以单例,依赖的就是私有的构造函数,因此使用时应避免与单例模式混用。

4 原型模式使用场景

后续若有落地经验,再来补充。

5 参考资料

《大话设计模式》
https://blog.csdn.net/jason0539/article/details/23158081
浅拷贝和深拷贝
https://blog.csdn.net/baiye_xing/article/details/71788741

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值