zoukankan      html  css  js  c++  java
  • 设计模式学习总结4 创建型4 Prototype原型模式

    Prototype原型模式(创建型)


    作用:

    原型模式通过克隆已存在的原型类实例新对象。原型模式有两点优势:1、因为复制对象比构造新对象要快,而且这些要复制的对象已加载在内存中,可以快速复制这些大对象来创建新的对象;2、可以保留大对象的固定的部分来复制新对象,简化子类的实例过程。

    Role
    The  Prototype pattern  creates  new  objects by  cloning one of  a few stored  prototypes. The Prototype pattern has two advantages: it speeds up the instantiation of very large, dynamically loaded classes (when copying objects is faster), and it keeps a record of identifiable parts of a large data structure that can be copied without knowing the subclass from which they were created.

    设计:

    IPrototype,定义可以被克隆原型接口
    Prototype,实现了原型接口,可以克隆出新对象
    PrototypeManager,原型管理器,管理各种可克隆类型和他们的关键词
    举例:
    IPrototype:可复制的功能
    Prototype:实现可复制功能的钢笔
    PrototypeManager:管理各种具有克隆自己功能的钢笔
    实现:

    实例1

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using PrototypePattern;

    namespace Prototype
    {
        [Serializable()]
        
    // Helper class used to create a second level data structure
        class DeeperData 
        {
             
    public string Data {getset;}

             
    public DeeperData(string s) 
             {
               Data 
    = s;
             }
             
    public override string ToString () 
             {
               
    return Data;
             }
        }
        


        [Serializable()]
        
    class  Prototype : IPrototype <Prototype>  
        {
             
    // Content members
             public string Country {getset;}
             
    public string Capital {getset;}
             
    public DeeperData Language {getset;}

             
    public Prototype (string country, string capital, string language) 
             {
               Country 
    = country;
               Capital 
    = capital;
               Language 
    = new DeeperData(language);
             }

             
    public override string ToString() 
             {
               
    return Country+"\t\t"+Capital+"\t\t->"+Language;
             }
        }
        
    class PrototypeManager 
        {
            
    public Dictionary <string, Prototype> prototypes
                
    = new Dictionary <string, Prototype>
                {
                    {
    "Germany",
                    
    new Prototype ("Germany""Berlin""German")},
                    {
    "Italy",
                    
    new Prototype ("Italy""Rome""Italian")},
                    {
    "Australia",
                    
    new Prototype ("Australia""Canberra""English")}
                };
        }
        
    //引用类型
        class RefTypeRectangle
        {
            
    public int Width;
            
    public int Height;
        }

        
    class Program
        {
            
    static void Report (string s, Prototype a, Prototype b) {
                 Console.WriteLine(
    "\n"+s);
                 Console.WriteLine(
    "Prototype "+a+"\nClone      "+b);
               }

            
    static void Main(string[] args)
            {
                
    #region 测试引用类型
                
    /*
                //有该程序可以看出,引用类型是相互影响的,因为他们是指向相同的内存空间实际的是操作同一个堆栈中的数据
                RefTypeRectangle refOne = new RefTypeRectangle();
                RefTypeRectangle refTwo = refOne;
                refOne.Width = 10;
                refOne.Height = 20;
                System.Console.WriteLine("引用类型测试:");
                System.Console.WriteLine("refTwo.Width:" + refTwo.Width);
                System.Console.WriteLine("refTwo.Height:" + refTwo.Height);
                System.Console.WriteLine("-----------------------------------");
                refTwo.Width = 15;
                refTwo.Height = 25;
                System.Console.WriteLine("refOne.Width:" + refOne.Width);
                System.Console.WriteLine("refOne.Height:" + refOne.Height);
                System.Console.WriteLine("-----------------------------------");



                string s1 = "s1";
                string s2 = s1;
                Console.WriteLine(s1);
                s2 = "s2";
                Console.WriteLine(s1);
                Console.ReadLine();
                
    */
                
    #endregion 
               PrototypeManager manager 
    = new PrototypeManager();
               Prototype  c2, c3;
      
               
    // Make a copy of Australia's data
               c2  =  manager.prototypes["Australia"].Clone();
               Report(
    "Shallow cloning Australia\n===============",
                   manager.prototypes[
    "Australia"], c2);
      
              
    // Change the capital of Australia to Sydney
               c2.Capital = "Sydney";
               Report(
    "Altered Clone's shallow state, prototype unaffected",
                   manager.prototypes[
    "Australia"], c2);
      
               
    // Change the language of Australia (deep data)
               c2.Language.Data = "Chinese";
               Report(
    "Altering Clone deep state: prototype affected *****",
                       manager.prototypes[
    "Australia"], c2);
      
               
    // Make a copy of Germany's data
               c3  =  manager.prototypes["Germany"].DeepCopy();
               Report(
    "Deep cloning Germany\n============",
                       manager.prototypes[
    "Germany"], c3);
      
               
    // Change the capital of Germany
               c3.Capital = "Munich";
               Report(
    "Altering Clone shallow state, prototype unaffected",
                       manager.prototypes[
    "Germany"], c3);
      
               
    // Change the language of Germany (deep data)
               c3.Language.Data = "Turkish";
               Report(
    "Altering Clone deep state, prototype unaffected",
                   manager.prototypes[
    "Germany"], c3);

               Console.ReadLine();
            }
        }
    }
    代码
    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.IO;

    namespace PrototypePattern 
    {
        
    // Prototype Pattern        Judith Bishop  Nov 2007
        
    // Serialization is used for the deep copy option
        
    // The type T must be marked with the attribute [Serializable()]

        [Serializable()]
        
    public abstract class IPrototype <T> 
        {

             
    // Shallow copy
             public T Clone() 
             {
                  
    return (T) this.MemberwiseClone();
             }

             
    //Deep Copy
               public T DeepCopy() 
               {
                   MemoryStream stream 
    = new MemoryStream();
                   BinaryFormatter formatter 
    = new BinaryFormatter();
                   formatter.Serialize(stream, 
    this);
                   stream.Seek(
    0, SeekOrigin.Begin);
                   T copy 
    = (T) formatter.Deserialize(stream);
                   stream.Close();
                   
    return copy;
               }
        }
    }

     使用场景:

    1、隐藏具体的类,不让客户端知道
    2、在运行时通过原型类添加或删除新类
    3、在系统中保持最小数量的类
    4、适用于在运行时改变数据的结构
    5、在C#3.0中使用深度克隆是非常简单的
    Use the Prototype pattern when…
    You want to:
    •  Hide concrete classes from the client.
    •  Add and remove new classes (via prototypes) at runtime.
    •  Keep the number of classes in the system to a minimum.
    •  Adapt to changing structures of data at runtime.

    总结:
    Prototype原型模式是一种创建型模式,解决“结构复杂对象”的创建工作。《设计模式》:使用原型实例创建指定的对象类型,然后通过拷贝这些原型来创建新的对象。原型模式是通过拷贝一个已存在的实例来创建新的对象,这一点和其他创建型模式不相同。
    Prototype原型模式的几个要点:
    1、Prototype原型模式隔离对象的使用者和具体类型之间的耦合关系,它同样要求这些要使用的类拥有“稳定的接口”。
    2、Prototype原型模式采用克隆原型的方法来创建对象,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象——所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方不断地Clone克隆。
    3、Prototype模式中的Clone方法可以利用Object类的浅拷贝MemberwiseClone()或者序列化来实现深拷贝DeepCopy()。
    这里面我们再来说说浅拷贝和深拷贝。对于Prototype模式是很重要的。浅拷贝和深拷贝的关键区别是对于对象内引用类型数据的拷贝。
    public class ClassB
    {}
    public class MainClass
    {
        int a;
        ClassB b;
    }

    我们用浅拷贝实现了两个对象MainClass1和MainClass2,对于MainClass1.a和MainClass2.a,他们是值类型,在MainClass2.a是新分配的内存,他们所有的内存空间是不一样,值是相等的,但是MainClass1.b和MainClass2.b,由于它们是引用类型,在浅拷贝时只是拷贝了MainClass1.b的地址给MainClass2的b成员,实际上MainClass1.b和MainClass2.b指向同一块内存。
    但如果我们用深拷贝,MainClass1.b和MainClass2.b指向的是不同的内存地址。一般利用序列化和反序列化来实现深拷贝来创建新的引用类型。

  • 相关阅读:
    Net基础篇_学习笔记_第十一天_面向对象(静态与非静态 static)
    Net基础篇_学习笔记_第十一天_面向对象(类)
    Net基础篇_学习笔记_第十一天_面向对象(面向过程与面向对象的区别/类的概念)
    学习笔记_第十天_方法_方法的综合练习---ref练习
    学习笔记_第十天_方法_方法的重载与递归
    学习笔记_第十天_方法_方法的三个高级参数
    学习笔记_第十天_方法_方法的三个高级参数
    MySQL 添加用户、删除用户与授权
    linux composer 安装与应用
    Note1
  • 原文地址:https://www.cnblogs.com/utopia/p/1675548.html
Copyright © 2011-2022 走看看