# Background knowledge 在Java中,Cloneable 介面是一個標記介面(Marker Interface,它們內部都沒有方法和屬性),實現Cloneable介面表示該對象能被克隆,能使用Object.clone()方法。 要實現克隆功能,需要滿足以下兩個條件: - 類實現 ...
Background knowledge
在Java中,Cloneable 介面是一個標記介面(Marker Interface,它們內部都沒有方法和屬性),實現Cloneable介面表示該對象能被克隆,能使用Object.clone()方法。
要實現克隆功能,需要滿足以下兩個條件:
- 類實現了 Cloneable 介面。
- 在類中重寫 clone() 方法。
What is Prototype Pattern
原型模式通過複製現有對象來創建新對象,而無需顯式地使用構造函數。原型模式允許動態創建對象,並且可以避免創建子類的複雜性。原型模式可以結合其他設計模式使用,例如工廠方法模式,以便更靈活地創建對象。
這個複製分為兩種模式:
-
深複製
深克隆(Deep Clone),深克隆是指創建一個新對象,並將原始對象的所有成員變數(無論是值類型還是引用類型)的值都複製到新對象中,包括引用類型成員變數所引用的對象。這樣,新對象和原始對象將擁有彼此獨立的成員變數副本,彼此之間的修改不會相互影響。深克隆涉及到遞歸地複製對象及其引用對象的過程,因此可能會比較複雜和耗時。
一般考慮使用深克隆,就是因為有可變的引用類型
會受影響, 既然引用類型無法被完全克隆,那麼我們可以考慮在引用類型所在的類也實現Cloneable介面。有多少個引用類型,就去實現多少個Cloneable介面。 -
淺複製
淺克隆(Shallow Clone),淺克隆是指創建一個新對象,並將原始對象的非引用類型成員變數的值複製到新對象中。對於引用類型成員變數,淺克隆將複製引用,使新對象和原始對象共用相同的引用對象。這意味著在淺克隆後,如果修改其中一個對象的引用類型成員變數,將會影響到另一個對象。因此,淺克隆只複製對象的錶面結構,而不涉及引用對象本身的複製。淺拷貝的情況下,原被克隆對象發生變化後,克隆對象的
基本數據類型
和不可變引用數據類型(String)
的數據不會發生影響,而一些其他欄位為可變的應用類型,只要克隆對象的內容隨著被克隆對象的變化發生了同樣的變化,說明兩個對象的屬性欄位指向同一個引用,才會造成這樣的結局。(我就碰到過因為對象被同事插進來的代碼導致對象發生了變更,代碼出現BUG的問題,後面是使用的深拷貝才消除同事的代碼對該對象的影響)。如果克隆的對象內沒有可變的引用對象,都是只用使用一些基礎類型,那麼直接用淺拷貝即可。
配合其他設計模式:
原型模式可以結合其他設計模式使用,例如工廠方法模式,以便更靈活地創建對象。
Key elements
- 抽象原型類
- 具體實現類
- Client
Example of Draw shape —— shallow clone
以下是一個簡單的淺克隆例子。
抽象原型類:
abstract class Shape implements Cloneable {
protected String type;
abstract void draw();
@Override
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
具體實現類:
// 具體原型類 - Rectangle
class Rectangle extends Shape {
public Rectangle() {
this.type = "Rectangle";
}
public void draw() {
System.out.println("Drawing a rectangle.");
}
}
// 具體原型類 - Circle
class Circle extends Shape {
public Circle() {
this.type = "Circle";
}
public void draw() {
System.out.println("Drawing a circle.");
}
}
Client:
// 客戶端代碼
public class Main {
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.
}
}
在上面的示例中,我們定義了抽象原型類 Shape,它包含了 clone() 方法和 draw() 方法。然後,我們實現了具體的原型類 Rectangle 和 Circle,它們繼承自 Shape 並實現了相應的方法。
在客戶端代碼中,我們首先創建了一個原始的 Rectangle 對象和一個原始的 Circle 對象。然後,我們分別對它們進行克隆,並得到克隆後的 Shape 對象。
通過原型模式,我們可以通過克隆(淺克隆)現有對象來創建新對象,而無需顯式地調用構造函數。這消除了重覆創建相似對象的需要,並提高了性能。
Reference
深克隆請參考這個文章
https://cloud.tencent.com/developer/article/1628044