设计模式_4_原型模式(对象的拷贝)

本文介绍了原型模式(PrototypePattern),一种创建型设计模式,用于高效地创建重复对象。讨论了浅拷贝和深拷贝的区别,并展示了如何通过重写Clonable的clone方法来实现。此外,还探讨了原型模式的操作流程、应用场景、优缺点以及代码实例,强调其在提升性能和避免构造对象资源消耗方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原形模式(PrototypePattern, 创建型模式,创建重复对象且保证性能, 对象的克隆)

通常使用原型模式创建一个原型接口, 用于获取创建对象的克隆, 对于浅拷贝与深拷贝不用纠结, 他们二者的区别就在于重写Clonable的clone方法

浅拷贝与深拷贝

浅拷贝: 直接调用Object的clone

public Object clone() {
		Object clone=null;
		try {
			clone=super.clone(); //不用管Object内部元素的情况直接调用Object的clone方法
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clone;
	}

深拷贝: 对clone对象( 此对象内部具有数组/集合/map等复合数据 )内部的数据再进行一次克隆

此处假设clone对象内部有一个ArrayList数组, ArrayList中存储A对象
	public Object clone() {
		Object clone=null;
		try {
			clone=super.clone();
			clone.getArray() = new ArrayList<A>(array.size()); //先将内部的ArrayList克隆出来
			for (int i=0; i < array.size(); i++){// 然后对ArrayList中的数据进行逐一克隆
				//从数组中获取每个元素, 然后进行克隆, 此处A对象内部没有复合数据, 最后将clone好的数据存入clone的array中
				clone.getArray().add( (A)array.get(i).clone() );
			}
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clone;
	}
因为只是调用Object的clone无法对克隆对象内部的数组类型进行复制, 所以还要针对拷贝对象的内部的数组再一次

操作流程

  • 使用方式
	原型模式通过拷贝一个现有对象生成新对象.
	浅拷贝实现Clonable接口, 重写clone方.
	深拷贝与浅拷贝一致, 也可以通过实现Serializable读取二进制流
		1.利用序列化产生的对象是对原对象的复制
		2.将对象序列化存入缓冲区, 然后将缓冲区对象读出, 用clone的引用指向该对象
  • 角色定义
原型角色:定义用于复制现有的实例来生成新的实例的方法(实现Cloneable接口的类)
具体原型角色:实现用于复制现有实例来生成新实例的方法(具有clone()方法的类)
使用者角色:维护一个注册表, 提供获取clone的类
  • 使用场景
1.资源优化, 类加载需要消耗很多资源, 性能和安全要求高的场景
2.通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模型
3.一个对象,多个修改者
4.大多数原型模式伴随工厂模式出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者
  • 优点
    性能提高,逃避构造函数的约束, 不推荐使用序列化处理clone

  • 缺点
    配备克隆操作需要对类的功能全盘考虑,对已有的类不一定很容易,特别是当一个类饮用不支持串行化的间接对象,或者引用含有循环结构(对象出现多层次的引用); 必须实现Cloneable接口

代码演示:

利用克隆, 事先将一些构造需要高代价的对象放入缓冲区, 然后在下次需要新的对象的时候直接去缓冲区拿( 缓冲区利用clone的方式给新对象, 而不是通过构造函数 )

package com.PrototypePattern;

import java.util.Hashtable;

public class ShapePrototypePattern {

	public static void main(String[] args) {
		//设计一个圆形的缓冲区
		Shape shape = new Circle();
		shape.setId("1");
		ShapeCache.loadCache(shape);
		
		//使用对应的图形缓冲区获得克隆对象clone, clone1, clone2
		Shape clonedShape=ShapeCache.getShape("1");
		System.out.println("Shape: "+clonedShape.hashCode());
		
		Shape clonedShape1=ShapeCache.getShape("1");
		System.out.println("Shape: "+clonedShape1.hashCode());
		
		Shape clonedShape2=ShapeCache.getShape("1");
		System.out.println("Shape: "+clonedShape2.hashCode());
	}

}
//针对不同的图形设计不同的缓冲区模块克隆模块
class ShapeCache{
	private static Hashtable<String,Shape>shapeMap=new Hashtable<String,Shape>();
	
	//使用get方法获得的图形都是原图形的克隆对象
	public static Shape getShape(String id) {
		Shape cachedShape=shapeMap.get(id);
		return (Shape)cachedShape.clone();
	}
	
	//将new出的对象放入Hashtable, 获得相应的图形直接获取clone
	public static void loadCache(Shape shape) {
		shapeMap.put(shape.getId(), shape);
	}
}

//原型角色,实现Cloneable接口,调用Object的clone方法
//当具体实现类需要clone的时候就可以直接调用clone
abstract class Shape implements Cloneable{
	private String id;
	protected String type;
	abstract public void draw(); 
	public String getType() {
		return type;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id=id;
	}
	public Object clone() {
		Object clone=null;
		try {
			clone=super.clone();
		}catch(CloneNotSupportedException e) {
			e.printStackTrace();
		}
		
		return clone;
	}
}

class Circle extends Shape{
	public Circle() {
		type="Circle";
	}
	@Override
	public void draw() {
		System.out.println("Circle");
		
	}
}
class Rectangle extends Shape{
	public Rectangle() {
		type="Rectangle";
	}
	@Override
	public void draw() {
		System.out.println("Rectangle");
		
	}
}
class Square extends Shape{
	public Square() {
		type="Square";
	}
	@Override
	public void draw() {
		System.out.println("Square");
		
	}
}

结语:

原型模式就是clone, 用于提高性能, 避免构造对象的时候加大资源的开销

上面有错, 还请指出, 如果认为我写的还不错, 还请点个赞, 多多支持一下, O(∩_∩)O~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值