科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道泛型集合类型,赋予集合业务意义,增强集合的抽象使用

泛型集合类型,赋予集合业务意义,增强集合的抽象使用

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

很多程序员不喜欢看到泛型的身影,他们看到“”这样的符号就会头痛并难受。

作者:ghost 来源:CSDN 2007年9月24日

关键字: ghost 泛型 集合 抽象使用

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共2页)

1、很多程序员不喜欢看到泛型的身影,他们看到“<>”这样的符号就会头痛并难受。受雇于人的我就只能竭尽我所能发起一场消除“<>”的行动,事实上这一点又变得有一些extend意义。

2、extend意义:赋予集合类更强的业务意义,搭配其自身所拥有的更多的自我描述解释操作的Action,类的行为将更加地具体,这样的类是OO中比较受欢迎的。

通常我们使用List<T>集合来操作,假设我们有一堆的类型为class Duck,我们可能就需要List<Duck>来对其进行描述了,这样看来,问题貌似还不那么棘手。但是当我们有一堆的ValueType或者string类型的值要被组成集合的时候我们会发现问题开始复杂了,我们可以定义List<string> studentNames来装载当前要装载的学生姓名,再用List<string> studentFatherNames来装载学生的父亲姓名,这样的结果将导致我们在某些情况比如有return value的时候,一个GetName()的方法将都被定义为List<string> GetName(),因此这里的List<string>将不那么“强类型”(事实上是强类型,但是这里我指的是那种没法鉴别的情况),也许你马上要指出我的错误,你会告诉我GetName()的方法名不好,方法的命名必须遵循“表文达意”之基本守则,但我们不能保证每个人都能有良好的素养和认真的态度。一旦这样的命名被使用着,我们就必须得担心着这个结果的正确性,而它们将不会在编译时被Checked,当我们的客户拿着程序来问你为什么学生的成绩单上总是印着他们父亲的考试分数的时候,我们是应该笑还是应该哭呢?

但如果我们换一个思路来做这件事情,会不会更好呢?

interface IName

{ string Name{get;} }

class Student:IName

class StudentParent:IName

//Example:

List<Student> students;

List<StudentParent> studentParents;

foreach(Student item in students)

{

item.Name;//deal with the students

}

foreach(StudentParent item in studentParents)

{

item.Name;//deal with the studentParents

}

这样我们将我们的类型更强烈化了

但有人觉得我的这个集合不会是一个复杂到需要用一个IName来指定一个string的字段,或者也不需要这么麻烦,我只想简单地将我的List<Student>表现地像List<string>一样,而又让它区别于List<StudentParent>所代表的List<string>(注意,这里的两个List<string>被要求有不同的抽象意义并表示相同的物理意义),我该如何做呢?

事实上这个问题被我们思考地过于复杂,我们不需要靠着前面的例子就可以想到这样的做法,那是因为我们明白了我们要做的就是上一段最后括号里的那句话,不同的抽象意义并表示相同的物理意义。这里的相同可以由您来指定,但它至少都表示了List<string>,我的意思是你可以实现相同意外的不同方法,比如单独为你的Student和StudentParent赋予不同的方法。

下面的例子正描述着这样的一般过程:

using System;
using System.Collections.Generic;
using System.Text;

namespace CA_CollectionBase
{
    //
    //The name of the Collection class should be defined like "BranchCollection/EmployeeCollection"
    //

    public sealed class SampleCollection : List<Sample> { }
    public sealed class Sample
    {
        private string value;
        public string Value
        {
            get { return this.value; }
        }
        public Sample(string item)
        {
            this.value = item;
        }

        //TODO:Describe other logic code
    }

    public sealed class StringCollection : List<string> { /*TODO:Describe other logic code*/ }
    public sealed class Int32Collection : List<Int32> { /*TODO:Describe other logic code*/ }
    public sealed class DoubleCollection : List<double> { /*TODO:Describe other logic code*/ }

    class Program
    {
        static void Main(string[] args)
        {
            //Object Type
            SampleCollection sc = new SampleCollection();
            sc.Add(new Sample("a"));
            sc.Add(new Sample("b"));
            foreach (Sample item in sc)
            {
                Console.WriteLine(item.Value);
            }

            //Special reference type
            StringCollection strs = new StringCollection();
            strs.Add("c");
            strs.Add("d");
            foreach (string item in strs)
            {
                Console.WriteLine(item);
            }

            //Simple ValueType
            Int32Collection ints = new Int32Collection();
            ints.Add(3);
            ints.Add(6);
            foreach (Int32 item in ints)
            {
                Console.WriteLine(item);
            }

            //Simple ValueType
            DoubleCollection doubles = new DoubleCollection();
            doubles.Add(3.6);
            doubles.Add(6.3);
            foreach (Double item in doubles)
            {
                Console.WriteLine(item);
            }
        }
    }
}

这些代码在Asp.net中同样能够得到广泛的应用,比如说我们绑定显示数据将会变得很简单

实现类ExampleClass并对其返回不同的类型,这些类型包括我们定义的集合本身,也包括通用的IList接口

public class ExampleClass
{
    public StringCollection GetStrings()
    {
        StringCollection strs = new StringCollection();
        strs.Add("string1");
        strs.Add("string2");
        strs.Add("string3");
        strs.Add("string4");
        return strs;
    }

    public SampleCollection GetSamplesAsCollection()
    {
        SampleCollection sc = new SampleCollection();
        sc.Add(new Sample("a"));
        sc.Add(new Sample("b"));
        sc.Add(new Sample("c"));
        sc.Add(new Sample("d"));
        return sc;
    }

    public IList<Sample> GetSamplesAsIList()
    {
        SampleCollection sc = new SampleCollection();
        sc.Add(new Sample("aList"));
        sc.Add(new Sample("bList"));
        sc.Add(new Sample("cList"));
        sc.Add(new Sample("dList"));
        return sc;
    }
}

namespace WebAppCollectionBaseTest
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            ExampleClass exp = new ExampleClass();
            //Step1
            this.GridView1.DataSource = exp.GetStrings();
            //Step2
            this.GridView1.DataSource = exp.GetSamplesAsCollection();
            //Step3
            this.GridView1.DataSource = exp.GetSamplesAsIList();
            this.GridView1.DataBind();
        }
    }
}

上面这段程序是不是就完美了呢?其实不然,当你真正去实现我注释中的TODO,去写自己的业务逻辑的时候会发现,我们并没有在期间建立起合理的连接,或者说上面那些只能做一个没有附加业务逻辑的类。我们既然是集合类,那么所有的业务逻辑都必然会操作到我们集合,但是按上面的Code我们只能在集合类的外部进行一些额外操作,至于集合类的内部,我们无法获得集合的实例(句柄Handler),因此我们也无法对它们进行操作,下面我用一个演化的过程来改进我们的类。

我们知道我们的类是继承了List<SampleClass>的,那么我们利用关键字base是否可以得到句柄呢?事实上是不可以的,因为我们的List类并没有传递相关的句柄给我们。本能的我们想构造一个类,并通过它来传递这个句柄给我们。另外一种想法,就是利用原来的类通过base.MemberwiseClone()不断提供旧有成员的克隆,并对它进行操作。不过很快后一种想法就因为居然是浅拷贝,而且只有在所有的数据被加载完之后MemberwiseClone才能返回全部的数据,否则期间将获得的数据将会是一个不完整(或者空)的数据集合。我们知道List<T>类实现了IList<T>接口,因此我们也需要模仿List<T>实现一个IList<T>接口,并返回List<T>句柄。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章