22 Jan 2006 @ 10:37 PM 
 

设计模式 — ProtoType

 

      问题:当我们在编写大型应用程序的时候,可能会遇到这样的情况:构造了一个基类,然后从该基类派生出子类。在子类的数目比较少的情况下,没有任何事情会发 生,但是如果当从某一个基类派生出的子类达到一定数目的时候,维护这些子类将是一件非常繁复的工作。

      解决方案:既然如此,干脆就不派生子类。无论如何,子类都是具有特性的基类的衍生,我们可以将这种特性直接在基类中反映出来。具体说来,就是实现不同种类的克隆。

      方法:传递进相关特性的参数,得到具有该特性的对象。

      其它:本示例代码以 C# 为示例语言,通过实现 ICloneable 和 ISerializable 来实现对象的浅表复制 (Shallow copy) 和深层复制 (Deep copy) 。这同时也是学习序列化的很好的演示示例。

附件:一个 XML 文档:



  
    Rui
    Tang
  
  
    Lichao
   Mu
  

using System;
using System.IO;
using System.Xml;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace ProtoType {
    /// 
    /// 用于存储每个员工的基本信息
    /// 
    public class Employee {
        private string firstName;
        private string lastName;

        public string FirstName {
            get { return this.firstName; }
            set { this.firstName = value; }
        }

        public string LastName {
            get { return this.lastName; }
            set { this.lastName = value; }
        }

        /// 
        /// 默认构造函数
        /// 
        public Employee() { }

        /// 
        /// 从序列化信息中得到数据
        /// 
        ///
序列化信息
        ///

        ///
序列化信息中字典的索引
        public Employee(SerializationInfo info, StreamingContext context, int index) {
            this.firstName = info.GetString("emp_fname" + index.ToString());
            this.lastName = info.GetString("emp_lname" + index.ToString());
        }

        /// 
        /// 将数据添加到序列化信息中
        /// 
        ///
序列化信息
        ///

        ///
序列化信息中字典的索引
        public void GetObjectData(SerializationInfo info, StreamingContext context, int index) {
            o.AddValue("emp_fname" + index.ToString(), firstName);
            info.AddValue("emp_lname" + index.ToString(), lastName);
        }
    }

    /// 
    /// 处理员工信息的类
    /// 
    [Serializable]
    public class EmployeeProcess : ICloneable,ISerializable {
        /// 
        /// 存储所有的员工
        /// 
        private ArrayList employeeArray = new ArrayList();

        /// 
        /// 默认构造函数,读取XML文档,并将员工添加到employeeArray中
        /// 
        public EmployeeProcess() {
            XmlDocument xmlDoc = new XmlDocument();
            Employee objEmp = null;

            xmlDoc.Load("Employees.xml");
            foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes) {
                objEmp = new Employee();
                objEmp.FirstName = node.SelectSingleNode("FirstName").InnerText;
                objEmp.LastName = node.SelectSingleNode("LastName").InnerText;
                employeeArray.Add(objEmp);
            }
        }

        /// 
        /// 反序列化必须要实现的一个方法,用于在反序列化时构造对象
        /// 
        ///
序列化信息
        ///

        public EmployeeProcess(SerializationInfo info, StreamingContext context) {
            int count;
            string temp = string.Empty;
            Employee objEmp = null;

            count = int.Parse(info.GetValue("emp_count",temp.GetType()).ToString());
            for (int i=0; i
        /// 实现浅表复制的克隆方法
        /// 
        /// 返回对象的引用
        public object Clone() {
            try { return this; }
            catch (Exception exce) {
                Console.WriteLine(exce.Message);
                return null;
            }
        }

        /// 
        /// 实现深层复制的克隆方法
        /// 
        ///
判断是否请求深层复制的标志量
        /// 返回对象的深层副本
        public object Clone(bool isDeep) {
            try {
                if (isDeep) { return CreateDeepCopy(); }
                else { return this.Clone(); }
            } catch (Exception exce) {
                Console.WriteLine(exce.Message);
                return null;
            }
        }

        /// 
        /// 序列化必须要实现的一个方法,将数据写到序列化信息中
        /// 
        ///
序列化信息
        ///

        public void GetObjectData(SerializationInfo info, StreamingContext context) {
            Employee objEmp;
            info.AddValue("emp_count",employeeArray.Count);
            for (int i=0; i
        /// 枚举所有员工的信息
        /// 
        /// 员工信息
        public string GetEmployeeInfo() {
            string strEmpData = string.Empty;
            for (int i=0; i
        /// 改变员工信息,用于测试深层复制和浅表复制的异同
        /// 
        public void ChangeEmployeeInfo() {
            foreach (Employee objEmp in employeeArray) {
                objEmp.FirstName = "FirstName";
                objEmp.LastName = "LastName";
            }
        }

        /// 
        /// 通过序列化创建对象的深层副本
        /// 
        /// 返回对象的深层副本
        private EmployeeProcess CreateDeepCopy() {
            EmployeeProcess objEmpCopy;
            Stream objStream;
            BinaryFormatter objBinFormatter = new BinaryFormatter();

            try {
                objStream = File.Open("Employees.bin",FileMode.Create);
                objBinFormatter.Serialize(objStream, this);
                objStream.Close();

                objStream = File.Open("Employees.bin",FileMode.Open);
                objEmpCopy = (EmployeeProcess)objBinFormatter.Deserialize(objStream);
                objStream.Close();

                return objEmpCopy;
            } catch (Exception exce) {
                Console.WriteLine(exce.Message);
                return null;
            }
        }
    }

    /// 
    /// 测试ProtoType
    /// 
    class TestProtoType {
        [STAThread]
        static void Main(string[] args) {
            //用正常的方法创建一个对象
            EmployeeProcess mainEmployeeProcess = new EmployeeProcess();
            //输出该对象的信息
            Console.WriteLine(mainEmployeeProcess.GetEmployeeInfo());

            //通过浅表复制得到一个刚才创建的对象的副本
            EmployeeProcess childEmployeeProcess1 = (EmployeeProcess)mainEmployeeProcess.Clone();
            //通过深层复制得到一个刚才创建的对象的副本
            EmployeeProcess childEmployeeProcess2 = (EmployeeProcess)mainEmployeeProcess.Clone(true);
            //改变用正常方法得到的对象的信息
            mainEmployeeProcess.ChangeEmployeeInfo();
            //输出浅表副本对象的信息,应该已经改变
            Console.WriteLine(childEmployeeProcess1.GetEmployeeInfo());
            //输出深成副本对象的信息,和原始的一样
            Console.WriteLine(childEmployeeProcess2.GetEmployeeInfo());

            Console.Read();
        }
    }
}
Tags Categories: 程序设计, 计算机科学与技术, 设计模式 Posted By: tangrui
Last Edit: 03 Dec 2006 @ 04 53 PM

E-mailPermalink
 

Responses to this post » (None)

 


Comments are open. Feel free to leave a comment below.


 

Leave A Comment ...

 

 XHTML:
You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
\/ More Options ...
Change Theme...
  • Users » 2
  • Posts/Pages » 83
  • Comments » 11
Change Theme...
  • VoidVoid
  • LifeLife « Default
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LiteLight
  • No Child Pages.
  • No Child Pages.
  • No Child Pages.
  • No Child Pages.