在OO設計中,對應於Relational Database的一筆資料,我們會用一個object,如Customer,但多筆資料呢?有些人會用DataSet,有些人會用List,這些方法都不錯,但若要設計自己的Collection:Customers type,那該怎麼做呢?
Abstract
在OO設計中,對應於Relational Database的一筆資料,我們會用一個object,如Customer,但多筆資料呢?有些人會用DataSet,有些人會用List<Customer>,這些方法都不錯,但若要設計自己的Collection:Customers type,那該怎麼做呢?
Introduction
使用DataSet(DataTable,DataReader....)或List<Customer>這些代表Collection,理論上並沒有什麼錯,事實上很多人也都這樣用,缺點就是比較沒有OO的flavor。理想上,既然有Customer class代表一筆資料,就應該有Customers class代表多筆資料,而N-Tiers間的傳輸應該是Customers collection,而非DataSet或List<Customer>。
要產生自己的Collection,有兩種方式,一個是.NET 1.0的方式,一個是.NET 2.0的方式。
.NET 1.0方式(在.NET 2.0仍然可以使用)
繼承CollectionBase,CollectionBase是一個abstract class,implement了IList ,ICollection,IEnumerable,已經為Collection做好了基礎架構,我們要做的就是overload this[]、IndexOf()、Add()、Remove()就好,其他的事情,CollectionBase已經幫我們做好了。

C#
1
/**//*
2
(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4
Filename : BuildOwnCollection1.cs
5
Compiler : Visual Studio 2005 / C# 2.0
6
Description : Demo how to build strong typed collection
7
Release : 06/19/2007 1.0
8
*/
9
using System;
10
using System.Collections;
11
12
public class Member
{
13
private string _name;
14
15
public Member()
{}
16
public Member(string name)
{
17
_name = name;
18
}
19
20
public string Name
{
21
get
{ return _name;}
22
set
{ _name = value;}
23
}
24
25
public override bool Equals(object obj)
{
26
Member member = (Member)obj;
27
return (_name == member.Name) ? true : false;
28
}
29
30
public override int GetHashCode()
{
31
return base.GetHashCode();
32
}
33
34
public static bool operator ==(Member member1, Member member2)
{
35
return member1.Equals(member2) ? true : false;
36
}
37
38
public static bool operator !=(Member member1, Member member2)
{
39
return !(member1 == member2);
40
}
41
}
42
43
public class Members : CollectionBase
{
44
public Member this[int index]
{
45
get
{ return (Member)List[index]; }
46
set
{ List[index] = value; }
47
}
48
49
public int IndexOf(Member member)
{
50
return this.List.IndexOf(member);
51
}
52
53
public void Add(Member member)
{
54
this.List.Add(member);
55
}
56
57
public void Remove(Member member)
{
58
if (this.IndexOf(member) != -1)
59
List.Remove(member);
60
}
61
}
62
63
public class main
{
64
public static void Main()
{
65
Members members = new Members();
66
67
// insert
68
members.Add(new Member("Clare"));
69
members.Add(new Member("Jessie"));
70
members.Add(new Member("Jingyi"));
71
72
// modify
73
int index = members.IndexOf(new Member("Jessie"));
74
if (index != -1) members[index] = new Member("Cerlina");
75
76
// delete
77
members.Remove(new Member("Clare"));
78
79
// search
80
index = members.IndexOf(new Member("Jingyi"));
81
if (index != -1) members.RemoveAt(index);
82
83
foreach(Member member in members)
{
84
Console.WriteLine(member.Name);
85
}
86
}
87
}
執行結果
Cerlina
在Member class中,25行到40行

public override bool Equals(object obj)
{
Member member = (Member)obj;
return (_name == member.Name) ? true : false;
}


public override int GetHashCode()
{
return base.GetHashCode();
}


public static bool operator ==(Member member1, Member member2)
{
return member1.Equals(member2) ? true : false;
}


public static bool operator !=(Member member1, Member member2)
{
return !(member1 == member2);
}
整體的目標是為了改寫object的比較方式,在.NET,預設是用reference比較object是否相同,但這對Collection的IndexOf(),Remove()有很大的影響,所以我override了Equals()和GetHashCode(),並對==和!=做了operator overloading。
CollectionBase原本都有實現IndexOf(),Add(),Remove(),但因只針對Object而非Member,所以針對了Member overload了IndexOf(),Add(),Remove(),另外使用了indexer是為了方便Collection的使用。
C++/CLI
1
/**//*
2
(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4
Filename : BuildOwnCollection1.cpp
5
Compiler : Visual C++ 8.0 / C++/CLI
6
Description : Demo how to build strong typed collection
7
Release : 06/19/2007 1.0
8
*/
9
#include "stdafx.h"
10
11
using namespace System;
12
using namespace System::Collections;
13
14
public ref class Member
{
15
private:
16
String^ _name;
17
18
public:
19
Member()
{}
20
Member(String^ name)
{
21
_name = name;
22
}
23
24
property String^ Name
{
25
String^ get()
{ return _name;}
26
void set(String^ value)
{ _name = value; }
27
}
28
29
virtual bool Equals(Object^ obj) override
{
30
Member^ member = safe_cast<Member^>(obj);
31
return (_name == member->Name) ? true : false;
32
}
33
34
virtual int GetHashCode() override
{
35
return Object::GetHashCode();
36
}
37
38
static bool operator==(Member^ member1, Member^ member2)
{
39
return member1->Equals(member2) ? true : false;
40
}
41
42
static bool operator!=(Member^ member1, Member^ member2)
{
43
return !(member1 == member2);
44
}
45
};
46
47
public ref class Members : CollectionBase
{
48
public:
49
property Member^ default[int]
{
50
Member^ get(int index)
{ return safe_cast<Member^>(List[index]); }
51
void set(int index, Member^ value)
{ List[index] = safe_cast<Member^>(value); }
52
}
53
54
int IndexOf(Member^ member)
{
55
return this->List->IndexOf(member);
56
}
57
58
void Add(Member^ member)
{
59
this->List->Add(member);
60
}
61
62
void Remove(Member^ member)
{
63
if (this->IndexOf(member) != -1)
64
List->Remove(member);
65
}
66
};
67
68
int main()
{
69
Members^ members = gcnew Members;
70
71
// insert
72
members->Add(gcnew Member("Clare"));
73
members->Add(gcnew Member("Jessie"));
74
members->Add(gcnew Member("Jingyi"));
75
76
// modify
77
int index = members->IndexOf(gcnew Member("Jessie"));
78
if (index != -1)
79
members[index] = gcnew Member("Cerlina");
80
81
// delete
82
members->Remove(gcnew Member("Clare"));
83
84
// search
85
index = members->IndexOf(gcnew Member("Jingyi"));
86
if (index != -1) members->RemoveAt(index);
87
88
for each(Member^ member in members)
89
Console::WriteLine(member->Name);
90
}
執行結果
Cerlina
.NET 2.0 (使用Collection<T>)
繼承Collection<Member>,因為是泛型,所以不用再overload IndexOf(),Add(),Remove(),也不用在定義indexer,因為泛型會直接使用Member,所以code非常精簡。
Collection<T>的架構頗複雜,implement了IEnumerable,IEnumerable<T>,ICollection,ICollection<T>,IList,IList<T>。

C#
1
/**//*
2
(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4
Filename : BuildOwnCollection2.cs
5
Compiler : Visual Studio 2005 / C# 2.0
6
Description : Demo how to build strong typed collection
7
Release : 06/19/2007 1.0
8
*/
9
using System;
10
using System.Collections.ObjectModel;
11
12
public class Member
{
13
private string _name;
14
15
public Member()
{ }
16
public Member(string name)
{
17
_name = name;
18
}
19
20
public string Name
{
21
get
{ return _name; }
22
set
{ _name = value; }
23
}
24
25
public override bool Equals(object obj)
{
26
Member member = (Member)obj;
27
return (_name == member.Name) ? true : false;
28
}
29
30
public override int GetHashCode()
{
31
return base.GetHashCode();
32
}
33
34
public static bool operator ==(Member member1, Member member2)
{
35
return member1.Equals(member2) ? true : false;
36
}
37
38
public static bool operator !=(Member member1, Member member2)
{
39
return !(member1 == member2);
40
}
41
}
42
43
public class Members : Collection<Member>
{
44
}
45
46
public class main
{
47
public static void Main()
{
48
Members members = new Members();
49
50
// insert
51
members.Add(new Member("Clare"));
52
members.Add(new Member("Jessie"));
53
members.Add(new Member("Jingyi"));
54
55
// modify
56
int index = members.IndexOf(new Member("Jessie"));
57
if (index != -1) members[index] = new Member("Cerlina");
58
59
// delete
60
members.Remove(new Member("Clare"));
61
62
// search
63
index = members.IndexOf(new Member("Jingyi"));
64
if (index != -1) members.RemoveAt(index);
65
66
foreach (Member member in members)
{
67
Console.WriteLine(member.Name);
68
}
69
}
70
}
執行結果
Cerlina
35行

public class Members : Collection<Member>
{
}
非常精簡,只需繼承Collection<Member>即可。
C++/CLI
1
/**//*
2
(C) OOMusou 2007 http://oomusou.cnblogs.com
3
4
Filename : BuildOwnCollection2.cpp
5
Compiler : Visual C++ 8.0 / C++/CLI
6
Description : Demo how to build strong typed collection by Generics
7
Release : 06/19/2007 1.0
8
*/
9
#include "stdafx.h"
10
11
using namespace System;
12
using namespace System::Collections::ObjectModel;
13
14
public ref class Member
{
15
private:
16
String^ _name;
17
18
public:
19
Member()
{ }
20
Member(String^ name)
{
21
_name = name;
22
}
23
24
public:
25
property String^ Name
{
26
String^ get()
{ return _name; }
27
void set(String^ value)
{ _name = value; }
28
}
29
30
virtual bool Equals(Object^ obj) override
{
31
Member^ member = safe_cast<Member^>(obj);
32
return (_name == member->Name) ? true : false;
33
}
34
35
virtual int GetHashCode() override
{
36
return Object::GetHashCode();
37
}
38
39
static bool operator ==(Member^ member1, Member^ member2)
{
40
return member1->Equals(member2) ? true : false;
41
}
42
43
static bool operator !=(Member^ member1, Member^ member2)
{
44
return !(member1 == member2);
45
}
46
};
47
48
public ref class Members : Collection<Member^>
{
49
};
50
51
int main()
{
52
Members^ members = gcnew Members;
53
54
// insert
55
members->Add(gcnew Member("Clare"));
56
members->Add(gcnew Member("Jessie"));
57
members->Add(gcnew Member("Jingyi"));
58
59
// modify
60
int index = members->IndexOf(gcnew Member("Jessie"));
61
if (index != -1) members[index] = gcnew Member("Cerlina");
62
63
// delete
64
members->Remove(gcnew Member("Clare"));
65
66
// search
67
index = members->IndexOf(gcnew Member("Jingyi"));
68
if (index != -1) members->RemoveAt(index);
69
70
for each (Member^ member in members)
{
71
Console::WriteLine(member->Name);
72
}
73
}
執行結果
Cerlina
Conclusion
泛型最基本的應用,也是最原始的應用,就是在container,若用OO,只能用多型(多態)的技術,讓container放Object type,進Container須轉型成Object,出Container需再轉回各type,若用泛型,就可直接將各type放進container,不需轉型,不只速度提升,且code也非常的精簡。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步