原型模式

定义:

       原型模式是用于创建重复的对象,同时又能保证性能,它提供了一种创建对象的最佳方式。

优点:

       1、性能提高

       2、逃避构造函数的约束

缺点:

       1、配备clone()方法需要对类的功能进行全盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类的引用不支持串行化的间接对象,或者引用含有循环结构的时候。

       2、必须实现Cloneable接口

组成部分:

       1、抽象原型类Prototype):它是声明克隆方法的接口,是所有具体原型类的公共父类,也可以是抽象类或者接口,甚至还可以是具体实现类。

       2、具体原型类Concrete Prototype):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。

       3、客户类Client):使用具体原型类中的clone()方法来复制新的对象。

注意事项:

       如果要克隆一个类的实例,那么这个类:

              1、必须实现Cloneable接口

              2、使用public访问修饰符重新定义object类的clone方法

实现方式:

       1、浅复制:基本数据类型进行传递,对引用数据类型进行引用传递般的拷贝,此为浅复制。 

       2、深复制:对基本数据类型进行传递,对引用数据类型创建一个新的对象,并复制其内容,此为深拷贝

当需要复制的类不包含复杂的对象类时

       步骤一: 被复制的类需要实现Clonenable接口(不实现的话在调用clone()方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)。

       步骤二:覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)。

     1、实现Clonenable接口并且覆盖clone()方法:

public class Student implements Cloneable{
	private String number;

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

	@Override
	protected Student clone() throws CloneNotSupportedException {		
		Student stu = null;
		try{
		    stu = (Student) super.clone();
		}catch(Exception e) {
		    e.printStackTrace();
		}
		return stu;
	}
	
}

       2、测试代码如下:

public class TestMain {

	public static void main(String[] args) throws CloneNotSupportedException {
		Student s1 = new Student();
		s1.setNumber("12345");
		Student s2 = s1.clone();
		System.out.println("学生1学号为"+s1.getNumber());
		System.out.println("学生2学号为"+s2.getNumber());
		
		s2.setNumber("54321");
		System.out.println("学生1学号为"+s1.getNumber());
		System.out.println("学生2学号为"+s2.getNumber());
	}
}

       3、输出结果如下:

       s1s2并不是同一个对象,如下所示,说明我们复制成功了,这里面采用的是深拷贝。

      System.out.println(stu1 == stu2); // false

当需要复制的类包含复杂的对象类时:

       1、我们新建一个Address类:

public class Address {

	private String detailsAddress;

	public String getDetailsAddress() {
		return detailsAddress;
	}

	public void setDetailsAddress(String detailsAddress) {
		this.detailsAddress = detailsAddress;
	}
	
}

       2、在Student类里面引入Address类:

public class Student implements Cloneable{
	private String number;
	private Address address;
	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}
	@Override
	protected Student clone() throws CloneNotSupportedException {
                Student stu = null;
		try{
		    stu = (Student) super.clone();
		}catch(Exception e) {
		    e.printStackTrace();
		}
		return stu;
	}
}

      3、 测试代码如下:

public class TestMain {

	public static void main(String[] args) throws CloneNotSupportedException {
		Address address = new Address();
		address.setDetailsAddress("天津");
		Student s1 = new Student();
		s1.setNumber("12345");
		s1.setAddress(address);
		
		Student s2 = s1.clone();
		System.out.println("学生1学号为"+s1.getNumber()+",地址为:"+s1.getAddress().getDetailsAddress());
		System.out.println("学生2学号为"+s2.getNumber()+",地址为:"+s1.getAddress().getDetailsAddress());
		
	}
}

       4、输出结果如下:

       乍一看没什么问题,真的是这样吗?我们在main方法中试着改变s2实例的detailsAddress

public class TestMain {

	public static void main(String[] args) throws CloneNotSupportedException {
		Address address = new Address();
		address.setDetailsAddress("天津");
		Student s1 = new Student();
		s1.setNumber("12345");
		s1.setAddress(address);
		
		Student s2 = s1.clone();
		s2.getAddress().setDetailsAddress("北京");
		System.out.println("学生1学号为"+s1.getNumber()+",地址为:"+s1.getAddress().getDetailsAddress());
		System.out.println("学生2学号为"+s2.getNumber()+",地址为:"+s1.getAddress().getDetailsAddress());
	}
}

       输出结果:

       这就奇怪了,怎么两个学生的地址都改变了?原因是浅复制只是复制了address变量的引用并没有真正的开辟另一块空间,将值复制后再将引用返回给新对象。所以,为了达到真正的复制对象,而不是纯粹引用复制。我们只需要将Address类可复制化,并且修改clone方法,完整代码如下:

public class Address implements Cloneable{

	private String detailsAddress;

	public String getDetailsAddress() {
		return detailsAddress;
	}

	public void setDetailsAddress(String detailsAddress) {
		this.detailsAddress = detailsAddress;
	}

	@Override
	protected Address clone() throws CloneNotSupportedException {
		return (Address) super.clone();
	}
}
public class Student implements Cloneable{
	private String number;
	private Address address;
	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}
	@Override
	protected Student clone(){
		Student stu = null;
		try{
		    stu = (Student) super.clone();
		    /*深度复制*/
		    stu.address =(Address)address.clone();
		}catch(Exception e) {
		    e.printStackTrace();
		}
		return stu;
	}
}

       测试代码如下:

public class TestMain {

	public static void main(String[] args) throws CloneNotSupportedException {
		Address address = new Address();
		address.setDetailsAddress("天津");
		Student s1 = new Student();
		s1.setNumber("12345");
		s1.setAddress(address);
		
		Student s2 = s1.clone();
		s2.getAddress().setDetailsAddress("北京");
		System.out.println("学生1学号为"+s1.getNumber()+",地址为:"+s1.getAddress().getDetailsAddress());
		System.out.println("学生2学号为"+s2.getNumber()+",地址为:"+s2.getAddress().getDetailsAddress());
	}
}

       输出结果如下: 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐的小三菊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值