One Design Pattern a Day - Prototype

One: mode definition

** The Prototype Pattern is used to create duplicate objects while maintaining performance. **This type of design pattern is a creational pattern, which provides an optimal way to create objects.

This pattern implements a prototype interface that is used to create a clone of the current object . This mode is used when the cost of directly creating the object is relatively high. For example, an object needs to be created after an expensive database operation. We can reduce database calls by caching the object, returning a clone of it on the next request, and updating the database when needed. That is: use a prototype instance to specify the type of object to create, and create a new object by copying this prototype.

Two: pattern structure

Archetype mode includes the following roles:

  • Prototype : Prototype class
  • ConcretePrototype : Concrete prototype class
    insert image description here

Three: Application - Cloning Sheep Problem

Now there is a sheep tom, name: tom, age: 1, color: white, please write a program to create 10 sheep with the same attributes as tom
sheep.
The traditional way to solve the problem of cloning sheep:

package com.atguigu.prototype;

public class Client {
    
    

public static void main(String[] args) {
    
    
// TODO Auto-generated method stub
//传统的方法
Sheep sheep = new Sheep("tom", 1, "白色");

Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
 

Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
//....

System.out.println(sheep); System.out.println(sheep2); System.out.println(sheep3); System.out.println(sheep4); System.out.println(sheep5);
//...
}

}

Advantages and disadvantages of traditional methods:

  1. The advantage is that it is easier to understand and easy to operate.
  2. When creating a new object, it is always necessary to re-acquire the properties of the original object. If the created object is complex, the efficiency is low.
  3. Always need to reinitialize the object instead of dynamically obtaining the runtime state of the object, not flexible enough
  4. Improved idea analysis

Idea: The Object class in Java is the root class of all classes. The Object class provides a clone() method, which can copy a Java object, but the Java class that needs to implement clone must implement an interface Cloneable. This interface Indicates that the class can be copied and has the ability to copy => prototype mode

Prototype mode to create cloned sheep:

Sheep class:

public class Sheep implements Cloneable {
    
    
	private String name;
	private int age;
	private String color;
	private String address = "蒙古羊";
	public Sheep friend; // 是对象, 克隆是会如何处理, 默认是浅拷贝

	public Sheep(String name, int age, String color) {
    
    
		super();
		this.name = name;
		this.age = age;
		this.color = color;
	}

	public String getName() {
    
    
		return name;
	}

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

	public int getAge() {
    
    
		return age;
	}

	public void setAge(int age) {
    
    

		this.age = age;
	}

	public String getColor() {
    
    
		return color;
	}

	public void setColor(String color) {
    
    
		this.color = color;
	}

	@Override
	public String toString() {
    
    
		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
	}

//克隆该实例,使用默认的 clone 方法来完成
	@Override
	protected Object clone() {
    
    

		Sheep sheep = null;
		try {
    
    
			sheep = (Sheep) super.clone();
		} catch (Exception e) {
    
    
// TODO: handle exception System.out.println(e.getMessage());
		}

// TODO Auto-generated method stub return sheep;
	}

}

Client class:

public class Client {
    
    

	public static void main(String[] args) {
    
    
		System.out.println("原型模式完成对象的创建");
// TODO Auto-generated method stub
		Sheep sheep = new Sheep("tom", 1, "白色");

		sheep.friend = new Sheep("jack", 2, "黑色");

		Sheep sheep2 = (Sheep) sheep.clone(); // 克隆Sheep sheep3 = (Sheep)sheep.clone(); //克隆Sheep sheep4 =
												// (Sheep)sheep.clone(); //克隆Sheep sheep5 = (Sheep)sheep.clone(); //克隆

		System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());

		System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());
		System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode());
		System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode());
	}

}

Four: deep copy and shallow copy

Shallow copy:

  1. For a member variable whose data type is a basic data type, shallow copy will directly pass the value, that is, copy the attribute value to a new object.
  2. For a member variable whose data type is a reference data type, for example, a member variable is an array, an object of a certain class, etc., then the shallow copy will be passed by reference, that is, only the reference value (memory address) of the member variable will be copied. One for the new object. Because in fact the member variables of both objects point to the same instance. In this case, modifying the member variable in one object will affect the value of the member variable in the other object

When there is a sheep object in the cloned sheep attribute, when the sheep is cloned multiple times, the attribute object reference in it will point to the same address.
Deep copy:

  1. Copy member variable values ​​of all primitive data types of an object

  2. Allocate storage space for all member variables of the reference data type, and copy the objects referenced by each member variable of the reference data type until all objects reachable by the object. That is to say, deep copying of an object requires a copy of the entire object (including the reference type of the object)

  3. Deep copy implementation 1: Override clone method to implement deep copy

  4. Deep copy implementation 2: Deep copy through object serialization (recommended)
    Code example:

public class DeepCloneableTarget implements Serializable, Cloneable {
    
    

	/**
	 
	
	*
	*/
	private static final long serialVersionUID = 1L;

	private String cloneName;

	private String cloneClass;

//构造器
	public DeepCloneableTarget(String cloneName, String cloneClass) {
    
    
		this.cloneName = cloneName;
		this.cloneClass = cloneClass;
	}

//因为该类的属性,都是 String ,  因此我们这里使用默认的 clone 完成即可
	@Override
	protected Object clone() throws CloneNotSupportedException {
    
    
		return super.clone();
	}
}

public class DeepProtoType implements Serializable, Cloneable {
    
    

	public String name; // String 属 性
	public DeepCloneableTarget deepCloneableTarget;// 引用类型

	public DeepProtoType() {
    
    
		super();
	}

//深拷贝 - 方式 1  使用 clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
    
    


Object deep = null;
//这里完成对基本数据类型(属性)和 String 的克隆
deep = super.clone();
//对引用类型的属性,进行单独处理
DeepProtoType deepProtoType = (DeepProtoType)deep;
deepProtoType.deepCloneableTarget	= (DeepCloneableTarget)deepCloneableTarget.clone();

// TODO Auto-generated method stub return deepProtoType;
 

}

//深拷贝 - 方式 2 通过对象的序列化实现 (推荐) public Object deepClone() {
    
    
//创建流对象ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null;

	try

	{
    
    

//序列化
		bos = new ByteArrayOutputStream();
		oos = new ObjectOutputStream(bos);
		oos.writeObject(this); // 当前这个对象以对象流的方式输出

//反序列化
		bis = new ByteArrayInputStream(bos.toByteArray());
		ois = new ObjectInputStream(bis);
		DeepProtoType copyObj = (DeepProtoType) ois.readObject();

		return copyObj;

	}catch(
	Exception e)
	{
    
    
// TODO: handle exception e.printStackTrace();
		return null;
	}finally
	{
    
    
//关闭流 try {
    
    
		bos.close();
		oos.close();
		bis.close();
		ois.close();
	}catch(Exception e2)
	{
    
    
// TODO: handle exception System.out.println(e2.getMessage());
	}
}

}

}

//Client.java
package com.atguigu.prototype.deepclone;


public class Client {
    
    
 

public static void main(String[] args) throws Exception {
    
    
// TODO Auto-generated method stub DeepProtoType p = new DeepProtoType(); p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");

//方式 1  完成深拷贝


//	DeepProtoType p2 = (DeepProtoType) p.clone();
//
//	System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
//	System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());

//方式 2  完成深拷贝
DeepProtoType p2 = (DeepProtoType) p.deepClone();


System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode()); System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());

}


}

Pros and cons of prototype mode:

1)	创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
2)	不用重新初始化对象,而是动态地获得对象运行时的状态
3)	如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
4)	在实现深克隆的时候可能需要比较复杂的代码
5)	缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则,这点请同学们注意.

Guess you like

Origin blog.csdn.net/qq_44867340/article/details/117885702