Background knowledge
在Java中,Cloneable 接口是一个标记接口(Marker Interface),用于指示实现了该接口的类可以进行克隆操作。它并没有定义任何方法,只是起到一个标记的作用。
要实现克隆功能,需要满足以下两个条件:
- 类实现了 Cloneable 接口。
- 在类中重写 clone() 方法。
What is Prototype Pattern
原型模式通过复制现有对象来创建新对象,而无需显式地使用构造函数。原型模式允许动态创建对象,并且可以避免创建子类的复杂性。原型模式可以结合其他设计模式使用,例如工厂方法模式,以便更灵活地创建对象。
这个复制分为两种模式:
-
深复制
深克隆(Deep Clone),深克隆是指创建一个新对象,并将原始对象的所有成员变量(无论是值类型还是引用类型)的值都复制到新对象中,包括引用类型成员变量所引用的对象。这样,新对象和原始对象将拥有彼此独立的成员变量副本,彼此之间的修改不会相互影响。深克隆涉及到递归地复制对象及其引用对象的过程,因此可能会比较复杂和耗时。 -
浅复制
浅克隆(Shallow Clone),浅克隆是指创建一个新对象,并将原始对象的非引用类型成员变量的值复制到新对象中。对于引用类型成员变量,浅克隆将复制引用,使新对象和原始对象共享相同的引用对象。这意味着在浅克隆后,如果修改其中一个对象的引用类型成员变量,将会影响到另一个对象。因此,浅克隆只复制对象的表面结构,而不涉及引用对象本身的复制。浅拷贝的情况下,原被克隆对象发生变化后,克隆对象的
基本数据类型
和不可变引用数据类型(String)
的数据不会发生影响,而一些其他字段为可变的应用类型,只要克隆对象的内容随着被克隆对象的变化发生了同样的变化,说明两个对象的属性字段指向同一个引用,才会造成这样的结局。(我就碰到过因为对象被同事插进来的代码导致对象发生了变更,代码出现BUG的问题,后面是使用的深拷贝才消除同事的代码对该对象的影响)。如果对象不需要修改属性,不需要做变更,那么用浅拷贝即可。
Key elements
- 抽象原型类
- 具体实现类
- Client
Example of Draw shape —— shallow clone
抽象原型类:
abstract class Shape implements Cloneable {
protected String type;
abstract void draw();
abstract void setType(String type);
@Override
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
/*
在上面的示例中,Shape 类实现了 Cloneable 接口,并重写了 clone() 方法。
在 Client类 main() 方法中,我们创建了一个原始对象 Circle,然后使用 clone() 方法创建了克隆对象 clone_Circle。
通过运行示例,我们可以看到原始对象和克隆对象初始时具有相同的值。然后,当我们修改克隆对象的值时,原始对象的值不受影响。
当然只是针对不可变引用数据类型,其他可变类型会改变。
需要注意的是,clone() 方法在 Object 类中是受保护的,因此在子类中重写时需要注意访问修饰符。
此外,对象克隆是浅拷贝的,即对于引用类型的成员变量,只复制引用而不是创建新对象。
如果需要实现深拷贝,需要在 clone() 方法中进行相应的处理。(在clone方法中调用Couple类的clone方法。)
总结来说,Cloneable 接口是一个标记接口,用于指示类可以进行对象克隆。
通过实现 Cloneable 接口并重写 clone() 方法,可以在Java中实现对象的浅拷贝。
*/
}
具体实现类:
class Circle extends Shape {
public Circle() {
this.type = "Circle";
}
public void draw() {
System.out.println("Drawing a circle.");
}
@Override
void setType(String type) {
this.type = type;
}
}
//
class Rectangle extends Shape {
public Rectangle() {
this.type = "Rectangle";
}
public void draw() {
System.out.println("Drawing a rectangle.");
}
@Override
void setType(String type) {
}
}
Client:
public class Client {
public static void main(String[] args) {
Shape rectangle = new Rectangle();
Shape circle = new Circle();
Shape clonedRectangle = (Shape) rectangle.clone();
Shape clonedCircle = (Shape) circle.clone();
System.out.println("Original Rectangle Type: " + rectangle.type);
rectangle.draw(); // Drawing a rectangle.
System.out.println("Cloned Rectangle Type: " + clonedRectangle.type);
clonedRectangle.draw(); // Drawing a rectangle.
System.out.println("Original Circle Type: " + circle.type);
circle.draw(); // Drawing a circle.
System.out.println("Cloned Circle Type: " + clonedCircle.type);
clonedCircle.draw(); // Drawing a circle.
clonedCircle.setType("MyisClonedCircle");
System.out.println("Cloned Circle Type: " + clonedCircle.type);
System.out.println("Original Circle Type: " + circle.type);
circle.draw(); // Drawing a circle.
}
}
- Creational Prototype Pattern Classcreational prototype pattern class creational singleton pattern class creational factory pattern class creational flyweight pattern class typescript prototype pattern prototype pattern javascript prototype class and composite structure pattern class behavioral template pattern class 原型prototype pattern模式