23种设计模式之原型模式

23种设计模式之原型模式

参考资料

下文如有错漏之处,敬请指正

一、简介

定义

通过克隆原型的实例对象,创建新的对象。

原理

原型实例实现Cloneable接口(来标示该对象是可克隆的)并重写clone()方法,通过 原型对象.clone() 方法创建新对象。

特点

  • 原型模式是一种创建型设计模式

  • 使用克隆创建的对象不会调用构造函数

  • 对于重量级的对象使用clone比new效率更高

优点

  • 性能优良

    原型模式是基于内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。

缺点

  • 逃避构造函数的约束

    由于原型模式是直接在内存中拷贝,因此构造函数不会被执行,减少了约束,可以通过原型模式破坏单例模式。

通用类图

在这里插入图片描述

  • Client:客户端对象,通过Prototype对象的clone方法,创建新的对象
  • Prototype:原型对象,实现Cloneable接口进行克隆标示并重写clone()方法

应用场景

  • 资源优化场景

    创建新对象成本较大,如类初始化需要占用较长的时间、占用太多的CPU资源或网络资源,新的对象可以使用原型模式获得。

  • 性能和安全要求的场景

    通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。

  • 保存对象状态

    如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式来实现。

  • 1个对象对多个修改者

    一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。

    在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的 方法创建一个对象,然后由工厂方法提供给调用者。

二、实现分类

浅克隆(浅拷贝)

  • 通过实现Cloneable接口进行克隆标示并重写clone()方法可以实现浅克隆。

  • 在浅克隆中,如果原型对象的属性是值类型,会复制其值;如果属性是引用类型,将复制其引用地址。

  • 注意:

    因为String类型是不可变数据类型,当它的值改变时,它将引用新的值的地址;原引用地址如果有对象引用就保留,否则会被回收。

    如果原型对象修改了String对象,不会影响克隆对象的String对象;反之,克隆对象修改了String对象,也不会影响原型对象的String对象。String字符串详解

    (在此可以将String类型当做值类型)

深克隆(深拷贝)

  • 通过重写clone()方法或对象序列化(Serialization)等方式来实现深克隆。

  • 在深克隆中,无论原型对象的属性是值类型还是引用类型,都将复制一份给克隆对象。

  • 注意:

    • 如果使用重写clone()方法实现深克隆,被克隆的对象需要实现Cloneable接口;

    • 如果使用序列化实现深克隆,被克隆的对象要实现Serializable接口。

浅克隆原型模式

需求:

一个牧羊人可以牧养多只羊,每只羊都大同小异,每只羊只有一个主人。

Prototype:Owner(牧羊人)、Sheep(羊)

Sheep:

package prototype.shallow;


public class Sheep implements Cloneable {
	private String name;

	public Sheep() {

	}

	public Sheep(String name) {
		this.name = name;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Sheep{" +
				"name='" + name + '\'' +
				'}';
	}
}

Owner:

package prototype.shallow;


import java.util.ArrayList;
import java.util.List;

public class Owner implements Cloneable {


	private String name;
	private List<Sheep> sheepList = new ArrayList<>();

	public Owner() {
	}

	public Owner(String name) {
		this.name = name;
	}


	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<Sheep> getSheepName() {
		return sheepList;
	}


	public void setSheepName(Sheep sheep) {
		this.sheepList.add(sheep);
	}


	@Override
	public String toString() {
		return "Owner{" +
				"name='" + name + '\'' +
				", sheepList=" + sheepList +
				'}';
	}
}

Client:

package prototype.shallow;


public class Client {
	public static void main(String[] args) throws CloneNotSupportedException {


		// 原型实例
		Owner owner = new Owner("Space");
		owner.setSheepName(new Sheep("肖恩1号"));

		// 克隆对象
		Owner clone = (Owner) owner.clone();
		clone.setName("Qi");
		clone.setSheepName(new Sheep("肖恩2号"));

		owner.setSheepName(new Sheep("肖恩3号"));


		System.out.println(owner);
		System.out.println(clone);
		/**
		 * 输出结果:
		 * Owner{name='Space', sheepList=[Sheep{name='肖恩1号'}, Sheep{name='肖恩2号'}, Sheep{name='肖恩3号'}]}
		 * Owner{name='Qi', sheepList=[Sheep{name='肖恩1号'}, Sheep{name='肖恩2号'}, Sheep{name='肖恩3号'}]}
		 * 因为是浅克隆,原型实例内部的引用类型的属性只会拷贝引用地址,因此两个Owner的sheepList的值是一样的
		 */

	}
}

深克隆原型模式

1. 重写clone()方法

需求:

一个牧羊人可以牧养多只羊,每只羊都大同小异,每只羊只有一个主人。

Prototype:Owner(牧羊人)、Sheep(羊)

Sheep:

package prototype.deep.Cloneable;

public class Sheep implements Cloneable{
	private String name;

	public Sheep() {

	}

	public Sheep(String name) {
		this.name = name;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Sheep{" +
				"name='" + name + '\'' +
				'}';
	}
}

Owner:

package prototype.deep.Cloneable;

import java.util.ArrayList;
import java.util.List;

public class Owner implements Cloneable {
	private String name;
	private ArrayList<Sheep> sheepList = new ArrayList<>();

	public Owner() {
	}

	public Owner(String name) {
		this.name = name;
	}


	@Override
	protected Owner clone() throws CloneNotSupportedException {
		// 对值类型的克隆
		Owner deep = (Owner) super.clone();
		// 对引用类型的克隆
		List<Sheep> sheepList = new ArrayList<>();
		deep.sheepList = (ArrayList<Sheep>) this.sheepList.clone();
		//返回克隆的对象
		return deep;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<Sheep> getSheepName() {
		return sheepList;
	}


	public void setSheepName(Sheep sheep) {
		this.sheepList.add(sheep);
	}


	@Override
	public String toString() {
		return "Owner{" +
				"name='" + name + '\'' +
				", sheepList=" + sheepList +
				'}';
	}
}

Client:

package prototype.deep.Cloneable;


public class Client {
	public static void main(String[] args) throws CloneNotSupportedException {
		// 原型实例
		Owner owner = new Owner("Space");
		owner.setSheepName(new Sheep("肖恩1号"));

		// 克隆对象
		Owner clone = owner.clone();
		clone.setName("Qi");
		clone.setSheepName(new Sheep("肖恩2号"));

		owner.setSheepName(new Sheep("肖恩3号"));


		System.out.println(owner);
		System.out.println(clone);

		/**
		 * 输出结果:
		 * Owner{name='Space', sheepList=[Sheep{name='肖恩1号'}, Sheep{name='肖恩3号'}]}
		 * Owner{name='Qi', sheepList=[Sheep{name='肖恩1号'}, Sheep{name='肖恩2号'}]}
		 */
	}
}
2. 使用对象的序列化

需求:

一个牧羊人可以牧养多只羊,每只羊都大同小异,每只羊只有一个主人。

Prototype:Owner(牧羊人)、Sheep(羊)

Sheep:

package prototype.deep.serilizable;

import java.io.*;

public class Sheep implements Serializable {
	private String name;

	public Sheep() {

	}

	public Sheep(String name) {
		this.name = name;
	}


	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Sheep{" +
				"name='" + name + '\'' +
				'}';
	}
}

Owner:

package prototype.deep.serilizable;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class Owner implements Serializable {

	private String name;
	private List<Sheep> sheepArrayList = new ArrayList<>();

	public Owner() {
	}

	public Owner(String name) {
		this.name = name;
	}


	protected Object deepClone() throws Exception {
		//将对象写入流中
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bao);
		oos.writeObject(this);

		//将对象从流中取出
		ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bis);
		
    return (ois.readObject());
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<Sheep> getSheepName() {
		return sheepArrayList;
	}


	public void setSheepName(Sheep sheep) {
		this.sheepArrayList.add(sheep);
	}


	@Override
	public String toString() {
		return "Owner{" +
				"name='" + name + '\'' +
				", sheepList=" + sheepArrayList +
				'}';
	}
}

Client:

package prototype.deep.serilizable;

public class Client {
	public static void main(String[] args) throws Exception {

		// 原型实例
		Owner owner = new Owner("Space");
		owner.setSheepName(new Sheep("肖恩1号"));

		// 克隆对象
		Owner clone = (Owner) owner.deepClone();
		clone.setName("Qi");
		clone.setSheepName(new Sheep("肖恩2号"));

		owner.setSheepName(new Sheep("肖恩3号"));


		System.out.println(owner);
		System.out.println(clone);

		/**
		 * 输出结果:
		 * Owner{name='Space', sheepList=[Sheep{name='肖恩1号'}, Sheep{name='肖恩3号'}]}
		 * Owner{name='Qi', sheepList=[Sheep{name='肖恩1号'}, Sheep{name='肖恩2号'}]}
		 */

	}
}

三、总结

  • 原型模式可以通过浅克隆和深克隆两种方式实现
  • 原型模式先产生出一个包含大量共有信息的类,然后拷贝出副本,修正细节信息, 建立了一个完整的个性对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值