天天看點

設計模式學習之原型模式(Prototype,建立型模式)(5)

設計模式學習之原型模式(Prototype,建立型模式)(5)

通過序列化的方式實作深拷貝

[Serializable]
    public class Person:ICloneable
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public List<Friend> FriendList { get; set; }
        public object Clone()
        {
            MemoryStream memoryStream = new MemoryStream();
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(memoryStream, this);
            memoryStream.Position = 0;
            Person p = (Person)formatter.Deserialize(memoryStream);
            return p;
        }
    }
    [Serializable]
    public class Friend
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }      

在開發中如果我們希望快速的建立一個對象,并且該對象和原有的對象擁有相同的資料,并且和原有的對象不相幹,那麼我們就可以這樣做

第一步:

假如我需要快速建立一個Person對象,然後和某個Person對象相同,如果我們我們隻需要Person對象中的屬性不引用其他資料資訊,可以使用淺拷貝;

如果我們需要Person對象中所有的資訊,包括引用的資料資訊,可以使用深拷貝

第二步:

在Person類中實作Cloneable接口,重寫clone()方法,如果是淺拷貝,隻需要直接調用父類的clone()方法就行,如果是深拷貝,需要在clone()方法中重新開辟引用字段所需的記憶體

代碼如下:

Person.java

package com.designpattern.prototype;

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

public class Person implements Cloneable {
    private String name;
    private int age;
    
    //朋友
    private List<String> friends;
    
    public List<String> getFriends() {
        return friends;
    }
    public void setFriends(List<String> friends) {
        this.friends = friends;
    }
    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;
    }
    
    
    
    /**
     * 實作淺拷貝
     */
//    protected Person clone(){
//        
//        try {
//            return (Person)super.clone();
//        } catch (CloneNotSupportedException e) {
//            e.printStackTrace();
//            return null;
//        }
//        
//    }
    
    /**
     * 實作深拷貝
     */
    protected Person clone(){
        
        try {
            List<String> newfriends = new ArrayList<String>();
            for (String friend : this.getFriends()) {
                newfriends.add(friend);
            }
            Person person = (Person)super.clone();
            person.setFriends(newfriends);
            return person;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
        
    }
}      

MainClass.java

package com.designpattern.prototype;

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

public class MainClass {

    public static void main(String[] args) {
        //假如我需要快速建立一個Person對象,然後和某個Person對象相同,如果我們我們隻需要Person對象中的屬性不引用其他資料資訊,可以使用淺拷貝
        //如果我們需要Person對象中所有的資訊,包括引用的資料資訊,可以使用深拷貝
        /*
         * 淺拷貝
         */
//        Person person = new Person();
//        person.setName("jack");
//        person.setAge(18);
//        
//        Person person2 = person.clone();//相當于重新開辟一塊記憶體空間,和person互不幹擾
//        person2.setName("jack1");
//        
//        System.out.println(person.getName());
//        System.out.println(person2.getName());
        
        Person person = new Person();
        person.setName("jack");
        person.setAge(18);
        List<String> friends = new ArrayList<String>();
        friends.add("p1");
        friends.add("p2");
        person.setFriends(friends);
        
        Person person2 = person.clone();
        person2.setName("jack1");
        friends.add("p3");//person 引用friends,friends改變,person的friends就會改變,如果用淺拷貝,person2也會跟着改變
        //如果用深拷貝,person2不會跟着改變,因為person2的friends和person的friends沒有指向同一塊記憶體
        
        
        System.out.println(person.getName());
        System.out.println(person2.getName());
        System.out.println(person.getFriends());
        System.out.println(person2.getFriends());
    }

}      

一、什麼是原型模式

Prototype模式是一種對象建立型模式,它采取複制原型對象的方法來建立對象的執行個體。使用Prototype模式建立的執行個體,具有與原型一樣的資料。

二、原型模式的特點

1. 由原型對象自身建立目标對象。也就是說,對象建立這一動作發自原型對象本身。

2.目标對象是原型對象的一個克隆。也就是說,通過Prototype模式建立的對象,不僅僅與原型對象具有相同的結構,還與原型對象具有相同的值。

3.根據對象克隆深度層次的不同,有淺度克隆與深度克隆。

三、原型模式應用場景

- 在建立對象的時候,我們不隻是希望被建立的對象繼承其基類的基本結構,還希望繼承原型對象的資料。

- 希望對目标對象的修改不影響既有的原型對象(深度克隆的時候可以完全互不影響)。

- 隐藏克隆操作的細節。很多時候,對對象本身的克隆需要涉及到類本身的資料細節。

.Net Framework源代碼中的模式之Prototype(原型模式)

轉載位址:http://kb.cnblogs.com/page/68814/

  用原型執行個體指定建立對象的種類,并且通過拷貝這個原型來建立新的對象。

設計模式學習之原型模式(Prototype,建立型模式)(5)

  以.NET Framework 2.0 System.Collections中類為例。

設計模式學習之原型模式(Prototype,建立型模式)(5)

  System.Collections. ICollection

public interface ICollection : IEnumerable

{

}

  System.Collections. ICloneable 

public interface ICloneable

  object Clone();

  System.Collections. Stack

public class Stack : ICollection, ICloneable

  public virtual Object Clone()

  {

    Stack s = new Stack(_size);

    s._size = _size;

    Array.Copy(_array, 0, s._array, 0, _size);

    s._version = _version;

    return s;

  }

  System.Collections. Queue

public class Queue : ICollection, ICloneable

  public virtual Object Clone()

   Queue q = new Queue(_size);

   q._size = _size;

   int numToCopy = _size;

   int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;

   Array.Copy(_array, _head, q._array, 0, firstPart);

   numToCopy -= firstPart;

   if (numToCopy > 0)

   Array.Copy(_array, 0, q._array, _array.Length - _head, numToCopy);

   q._version = _version;

   return q;

  調用代碼

public class Client

  public static void Main()

    Stack myStack = new Stack();

    myStack.Push("Hello");

    myStack.Push("World");

    myStack.Push("!");

    Stack myStackCopy = (Stack)myStack.Clone(); 

    foreach (string s in myStackCopy)

    {

      Console.Write(s);

    }

    Console.WriteLine();

    Console.ReadLine();

  在.NET Framework中,可以通過實作ICloneable接口來實作原型模式,ICloneable接口隻有一個Clone方法。克隆的實作方法有兩種:淺拷貝(shallow copy)與深拷貝(deep copy)。

  淺拷貝是指當對象的字段值被拷貝時,字段引用的對象不會被拷貝。例如,如果一個對象有一個指向字元串的字段,并且我們對該對象做了一個淺拷貝,那麼兩個對象将引用同一個字元串。而深拷貝是對對象執行個體中字段引用的對象也進行拷貝的一種方式,是以如果一個對象有一個指向字元串的字段,并且我們對該對象做了一個深拷貝的話,我們将建立一個新的對象和一個新的字元串--新對象将引用新字元串。需要注意的是執行深拷貝後,原來的對象和新建立的對象不會共享任何東西;改變一個對象對另外一個對象沒有任何影響。

  對于值類型,淺拷貝通過指派等操作直接實作,将對象中的值類型的字段拷貝到新的對象中;深拷貝和淺拷貝相同,通過指派等操作直接實作,将對象中的值類型的字段拷貝到新的對象中。 對于引用類型,淺拷貝通過MemberwiseClone 方法建立一個淺副本,方法是建立一個新對象,如果字段是值類型的,則對該字段執行逐位複制,如果字段是引用類型,則複制引用原始對象,與原對象引用同一對象;深拷貝拷貝對象應用,也拷貝對象實際内容,也就是建立了一個新的對象,改變新對象不會影響到原始對象的内容。

  在下列情況下,應當使用Prototype模式:

  • 當一個系統應該獨立于它的産品建立,構成和表示時;
  • 當要執行個體化的類是在運作時刻指定時,例如,通過動态裝載;
  • 為了避免建立一個與産品類層次平行的工廠類層次時;
  • 當一個類的執行個體隻能有幾個不同狀态組合中的一種時。建立相應數目的原型并克隆它們可能比每次用合适的狀态手工執行個體化該類更友善一些。