通过序列化的方式实现深拷贝

  1. [Serializable]
  2. public class Person:ICloneable
  3. {
  4. public string Name { get; set; }
  5. public int Age { get; set; }
  6. public List<Friend> FriendList { get; set; }
  7. public object Clone()
  8. {
  9. MemoryStream memoryStream = new MemoryStream();
  10. BinaryFormatter formatter = new BinaryFormatter();
  11. formatter.Serialize(memoryStream, this);
  12. memoryStream.Position = ;
  13. Person p = (Person)formatter.Deserialize(memoryStream);
  14. return p;
  15. }
  16. }
  17. [Serializable]
  18. public class Friend
  19. {
  20. public string Name { get; set; }
  21. public int Age { get; set; }
  22. }

在开发中如果我们希望快速的创建一个对象,并且该对象和原有的对象拥有相同的数据,并且和原有的对象不相干,那么我们就可以这样做

第一步:

假如我需要快速创建一个Person对象,然后和某个Person对象相同,如果我们我们只需要Person对象中的属性不引用其他数据信息,可以使用浅拷贝;

如果我们需要Person对象中所有的信息,包括引用的数据信息,可以使用深拷贝

第二步:

在Person类中实现Cloneable接口,重写clone()方法,如果是浅拷贝,只需要直接调用父类的clone()方法就行,如果是深拷贝,需要在clone()方法中重新开辟引用字段所需的内存

代码如下:

Person.java

  1. package com.designpattern.prototype;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. public class Person implements Cloneable {
  7. private String name;
  8. private int age;
  9.  
  10. //朋友
  11. private List<String> friends;
  12.  
  13. public List<String> getFriends() {
  14. return friends;
  15. }
  16. public void setFriends(List<String> friends) {
  17. this.friends = friends;
  18. }
  19. public String getName() {
  20. return name;
  21. }
  22. public void setName(String name) {
  23. this.name = name;
  24. }
  25. public int getAge() {
  26. return age;
  27. }
  28. public void setAge(int age) {
  29. this.age = age;
  30. }
  31.  
  32. /**
  33. * 实现浅拷贝
  34. */
  35. // protected Person clone(){
  36. //
  37. // try {
  38. // return (Person)super.clone();
  39. // } catch (CloneNotSupportedException e) {
  40. // e.printStackTrace();
  41. // return null;
  42. // }
  43. //
  44. // }
  45.  
  46. /**
  47. * 实现深拷贝
  48. */
  49. protected Person clone(){
  50.  
  51. try {
  52. List<String> newfriends = new ArrayList<String>();
  53. for (String friend : this.getFriends()) {
  54. newfriends.add(friend);
  55. }
  56. Person person = (Person)super.clone();
  57. person.setFriends(newfriends);
  58. return person;
  59. } catch (CloneNotSupportedException e) {
  60. e.printStackTrace();
  61. return null;
  62. }
  63.  
  64. }
  65. }

MainClass.java

  1. package com.designpattern.prototype;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. public class MainClass {
  7.  
  8. public static void main(String[] args) {
  9. //假如我需要快速创建一个Person对象,然后和某个Person对象相同,如果我们我们只需要Person对象中的属性不引用其他数据信息,可以使用浅拷贝
  10. //如果我们需要Person对象中所有的信息,包括引用的数据信息,可以使用深拷贝
  11. /*
  12. * 浅拷贝
  13. */
  14. // Person person = new Person();
  15. // person.setName("jack");
  16. // person.setAge(18);
  17. //
  18. // Person person2 = person.clone();//相当于重新开辟一块内存空间,和person互不干扰
  19. // person2.setName("jack1");
  20. //
  21. // System.out.println(person.getName());
  22. // System.out.println(person2.getName());
  23.  
  24. Person person = new Person();
  25. person.setName("jack");
  26. person.setAge();
  27. List<String> friends = new ArrayList<String>();
  28. friends.add("p1");
  29. friends.add("p2");
  30. person.setFriends(friends);
  31.  
  32. Person person2 = person.clone();
  33. person2.setName("jack1");
  34. friends.add("p3");//person 引用friends,friends改变,person的friends就会改变,如果用浅拷贝,person2也会跟着改变
  35. //如果用深拷贝,person2不会跟着改变,因为person2的friends和person的friends没有指向同一块内存
  36.  
  37. System.out.println(person.getName());
  38. System.out.println(person2.getName());
  39. System.out.println(person.getFriends());
  40. System.out.println(person2.getFriends());
  41. }
  42.  
  43. }

一、什么是原型模式

Prototype模式是一种对象创建型模式,它采取复制原型对象的方法来创建对象的实例。使用Prototype模式创建的实例,具有与原型一样的数据。

二、原型模式的特点

1. 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。

2.目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。

3.根据对象克隆深度层次的不同,有浅度克隆与深度克隆。

三、原型模式应用场景

- 在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据。

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

- 隐藏克隆操作的细节。很多时候,对对象本身的克隆需要涉及到类本身的数据细节。

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

转载地址:http://kb.cnblogs.com/page/68814/

  用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

  以.NET Framework 2.0 System.Collections中类为例。

  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模式:

  • 当一个系统应该独立于它的产品创建,构成和表示时;
  • 当要实例化的类是在运行时刻指定时,例如,通过动态装载;
  • 为了避免创建一个与产品类层次平行的工厂类层次时;
  • 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

设计模式学习之原型模式(Prototype,创建型模式)(5)的更多相关文章

  1. 设计模式学习之单例模式(Singleton,创建型模式)(4)

    假如程序中有一个Person类,我的需求就是需要在整个应用程序中只能new一个Person,而且这个Person实例在应用程序中进行共享,那么我们该如何实现呢? 第一步: 新建一个Person类,类中 ...

  2. 设计模式05: Prototype 原型模式(创建型模式)

    Prototype 原型模式(创建型模式) 依赖关系的倒置抽象不应该依赖于实现细节,细节应该依赖于抽象.对所有的设计模式都是这样的. -抽象A直接依赖于实现细节b -抽象A依赖于抽象B,实现细节b依赖 ...

  3. 原型模式 prototype 创建型 设计模式(七)

    原型模式  prototype 意图 用原型实例指定需要创建的对象的类型,然后使用复制这个原型对象的方法创建出更多同类型的对象   显然,原型模式就是给出一个对象,然后克隆一个或者更多个对象 小时候看 ...

  4. Prototype,创建型模式

    读书笔记_探索式测试_混合探索式测试   一.测试场景 1.讲述用户故事 2.描述需求 3.演示产品功能 4.演示集成场景 5.描述设置和安装 6.描述警告和出错情况 二.使用基于场景的探索式测试 1 ...

  5. 设计模式04: Factory Methord 工厂方法模式(创建型模式)

    Factory Methord 工厂方法模式(创建型模式) 从耦合关系谈起耦合关系直接决定着软件面对变化时的行为 -模块与模块之间的紧耦合使得软件面对变化时,相关的模块都要随之变更 -模块与模块之间的 ...

  6. 设计模式03: Builder 生成器模式(创建型模式)

    Builder生成器模式(创建型模式) Builder模式缘起假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分富于变化.如果使用最直观的设计方法,每个房屋部分的变化,都将 ...

  7. (转)Java经典设计模式(1):五大创建型模式(附实例和详解)

    原文出处: 小宝鸽 一.概况 总体来说设计模式分为三大类: (1)创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. (2)结构型模式,共七种:适配器模式.装饰器模式.代 ...

  8. 设计模式01: Singleton 单例模式(创建型模式)

    Singleton 单例模式(创建型模式) 动机(Motivation)当进行软件开发是会有这样一种需求:在系统中只有存在一个实例才能确保它们的逻辑正确性.以及良好的效率.这应该是类设计者的责任,而不 ...

  9. Java设计模式——建造者模式(创建型模式)

    概述   建造者模式也称为生成器模式,是一种对象创建型模式,它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象.   建造者模式意在为重叠构造 ...

随机推荐

  1. JSP 使用

    JSP教程: http://www.w3cschool.cc/jsp/jsp-tutorial.html jsp语法: 任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依 ...

  2. hdu 2050 折线分割平面

    训练递推用题,第一次做这个题,蒙的,而且对了. #include <stdio.h> int main(void) { int c,a; scanf("%d",& ...

  3. Linux之Sed命令详解(总结一些实用例子)

    简介 sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的 ...

  4. [LeetCode] Best Time to Buy and Sell Stock III

    将Best Time to Buy and Sell Stock的如下思路用到此题目 思路1:第i天买入,能赚到的最大利润是多少呢?就是i + 1 ~ n天中最大的股价减去第i天的. 思路2:第i天买 ...

  5. ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇(转)

    ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇   阅读目录 ASP.NET Identity 前世今生 建立 ASP.NET Identity 使用ASP.NET ...

  6. MyISAM 与 InnoDB 的区别

    MyISAM 和 InnoDB 讲解 InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型不支持事务处理等高级处 ...

  7. Button控件常用api

    加载按钮的纹理.loadTextures (const std::string &normal, const std::string &selected, const std::str ...

  8. HDU 4857 逃生 (优先队列+反向拓扑)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4857 解题报告:有n个点,有m个条件限制,限制是像这样的,输入a  b,表示a必须排在b的前面,如果不 ...

  9. 开机提示grub可咋办啊

    导读 GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统.GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数. 1 ...

  10. 2d背景循环

    using UnityEngine; using System.Collections; /// <summary> /// 2d背景循环滚动 /// </summary> p ...