本文背景是下面3篇文章:
看有道难题比赛有恶心感 ,付源码挑战,博客园目前纯速度最快。
正文:
1 public class Cell
2 {
3 private class EmptyCell : Cell
4 {
5 public override Int32 Count
6 {
7 get { return 0; }
8 set { }
9 }
10 }
11
12 public static readonly Cell Empty;
13
14 static Cell()
15 {
16 Empty = new EmptyCell();
17 }
18
19 public virtual Int32 Count { get; set; }
20
21 public Cell North { get; set; }
22 public Cell South { get; set; }
23 public Cell East { get; set; }
24 public Cell West { get; set; }
25 public Cell NorthWest { get; set; }
26 public Cell NorthEast { get; set; }
27 public Cell SouthWest { get; set; }
28 public Cell SouthEast { get; set; }
29
30 public Cell(Int32 count)
31 {
32 this.Count = count;
33 North = South = East = West = NorthEast = NorthWest = SouthEast = SouthWest = Cell.Empty;
34 }
35
36 public Cell()
37 : this(0)
38 {
39 }
40
41 public Int32 Degree
42 {
43 get { return North.Count + South.Count + East.Count + West.Count + NorthWest.Count + NorthEast.Count + SouthWest.Count + SouthEast.Count; }
44 }
45 }
每一个萝卜坑维护有它和别的萝卜坑之间的关系。这样,每一个萝卜坑的Degree属性即是它的特殊程度,很容易算,不必知道萝卜坑在农田中的坐标。这样,萝卜坑就不必知道农田的存在了。为了避免边界条件,这里引入空对象,即EmptyCell。
然后是农田类Farmland:
1 public class Farmland
2 {
3 Cell[][] _cells;
4
5 public Int32 Width { get; private set; }
6 public Int32 Length { get; private set; }
7
8 public Farmland(Int32 length, Int32 width)
9 {
10 if (length < 0) throw new ArgumentOutOfRangeException("length");
11 if (width < 0) throw new ArgumentOutOfRangeException("width");
12
13 Length = length;
14 Width = width;
15 InitCells();
16 }
17
18 private void InitCells()
19 {
20 _cells = new Cell[Length][];
21 for (Int32 x = 0; x < Length; x++)
22 {
23 Cell[] line = new Cell[Width];
24 for (Int32 y = 0; y < Width; y++)
25 {
26 line[y] = new Cell();
27 }
28 _cells[x] = line;
29 }
30
31 InitRelationships();
32 }
33
34 private void InitRelationships()
35 {
36 for (Int32 i = 0; i < Length; i++)
37 {
38 for (Int32 j = 0; j < Width; j++)
39 {
40 InitRelationship(i, j);
41 }
42 }
43 }
44
45 private void InitRelationship(Int32 x, Int32 y)
46 {
47 Cell cell = GetCell(x, y);
48 cell.North = GetCell(x, y - 1);
49 cell.South = GetCell(x, y + 1);
50 cell.West = GetCell(x - 1, y);
51 cell.East = GetCell(x + 1, y);
52 cell.NorthWest = GetCell(x - 1, y - 1);
53 cell.NorthEast = GetCell(x + 1, y - 1);
54 cell.SouthEast = GetCell(x + 1, y + 1);
55 cell.SouthWest = GetCell(x - 1, y + 1);
56 }
57
58 private Cell GetCell(Int32 x, Int32 y)
59 {
60 if (x >= 0 && y >= 0 && x < Length && y < Width)
61 return this[x][y];
62 else
63 return Cell.Empty;
64 }
65
66 public Cell[] this[Int32 index]
67 {
68 get { return _cells[index]; }
69 }
70
71 public Int32 CountDegree(Int32 min, Int32 max)
72 {
73 Int32 count = 0;
74 for (Int32 x = 0; x < this.Length; x++)
75 {
76 for (Int32 y = 0; y < this.Width; y++)
77 {
78 Int32 c = this[x][y].Degree;
79 if (c >= min && c <= max) count++;
80 }
81 }
82 return count;
83 }
84
85 public static Farmland Create(String[] fields)
86 {
87 Farmland farmland = new Farmland(fields[0].Length, fields.Length);
88
89 for (Int32 y = 0; y < fields.Length; y++)
90 {
91 String tmp = fields[y];
92 for (Int32 x = 0; x < tmp.Length; x++)
93 {
94 farmland[x][y].Count = tmp[x] - '0';
95 }
96 }
97
98 return farmland;
99 }
100 }
农田在初始化时就自动将萝卜坑之间的关系确定了。
哦,测试一下:
1 static void Main(string[] args)
2 {
3 Farmland land0 = Farmland.Create(new string[] { "924", "231", "390", "910", "121" });
4 Console.WriteLine("land0: " + land0.CountDegree(31,36));
5 Farmland land1 = Farmland.Create(new string[] { "2309", "0239", "2314" });
6 Console.WriteLine("land1: " + land1.CountDegree(5, 7));
7 Console.Read();
8 }
结果:
2 land1: 3
这样写是不是更容易扩展,更容易维护?OO是朴素的,而不是教条的。
--------------------------------------------------------------------------------------------------
似乎无法2小时内再发第二篇,那就接着这个向下写吧。
下面,使用泛型将这个问题再一般化。这里没有萝卜坑,没有农田,只有Cell和Cell容器MatrixCellContainer。
亮代码 :
1 public class Cell<T>
2 {
3 private class EmptyCell : Cell<T>
4 {
5 public override T Entity
6 {
7 get { return default(T); }
8 set { }
9 }
10 }
11
12 public static readonly Cell<T> Empty;
13
14 static Cell()
15 {
16 Empty = new EmptyCell();
17 }
18
19 public virtual T Entity { get; set; }
20
21 public Cell<T> North { get; set; }
22 public Cell<T> South { get; set; }
23 public Cell<T> East { get; set; }
24 public Cell<T> West { get; set; }
25 public Cell<T> NorthWest { get; set; }
26 public Cell<T> NorthEast { get; set; }
27 public Cell<T> SouthWest { get; set; }
28 public Cell<T> SouthEast { get; set; }
29
30 public Cell(T entity)
31 {
32 this.Entity = entity;
33 North = South = East = West = NorthEast = NorthWest = SouthEast = SouthWest = Cell<T>.Empty;
34 }
35
36 public Cell()
37 : this(default(T))
38 {
39 }
40 }
41
42 public class MatrixCellContainer<T> : IEnumerable<List<Cell<T>>>
43 {
44 List<List<Cell<T>>> _cells;
45 public Int32 Width { get; private set; }
46 public Int32 Length { get; private set; }
47
48 public MatrixCellContainer(Int32 length, Int32 width)
49 {
50 if (length < 0) throw new ArgumentOutOfRangeException("length");
51 if (width < 0) throw new ArgumentOutOfRangeException("width");
52
53 Length = length;
54 Width = width;
55 InitCells();
56 }
57
58 private void InitCells()
59 {
60 _cells = new List<List<Cell<T>>>(Length);
61 for (Int32 x = 0; x < Length; x++)
62 {
63 List<Cell<T>> line = new List<Cell<T>>(Width);
64 for (Int32 y = 0; y < Width; y++)
65 {
66 line.Add(new Cell<T>());
67 }
68 _cells.Add(line);
69 }
70
71 InitRelationships();
72 }
73
74 private void InitRelationships()
75 {
76 for (Int32 i = 0; i < Length; i++)
77 {
78 for (Int32 j = 0; j < Width; j++)
79 {
80 InitRelationship(i, j);
81 }
82 }
83 }
84
85 private void InitRelationship(Int32 x, Int32 y)
86 {
87 Cell<T> cell = GetCell(x, y);
88 cell.North = GetCell(x, y - 1);
89 cell.South = GetCell(x, y + 1);
90 cell.West = GetCell(x - 1, y);
91 cell.East = GetCell(x + 1, y);
92 cell.NorthWest = GetCell(x - 1, y - 1);
93 cell.NorthEast = GetCell(x + 1, y - 1);
94 cell.SouthEast = GetCell(x + 1, y + 1);
95 cell.SouthWest = GetCell(x - 1, y + 1);
96 }
97
98 private Cell<T> GetCell(Int32 x, Int32 y)
99 {
100 if (x >= 0 && y >= 0 && x < Length && y < Width)
101 return this[x][y];
102 else
103 return Cell<T>.Empty;
104 }
105
106 public List<Cell<T>> this[Int32 index]
107 {
108 get { return _cells[index]; }
109 }
110
111 //public static CellContainer<T> Create<T>(String[] fields)
112 //{
113 // CellContainer farmland = new CellContainer(fields[0].Length, fields.Length);
114
115 // for (Int32 y = 0; y < fields.Length; y++)
116 // {
117 // String tmp = fields[y];
118 // for (Int32 x = 0; x < tmp.Length; x++)
119 // {
120 // farmland[x][y].Count = tmp[x] - '0';
121 // }
122 // }
123
124 // return farmland;
125 //}
126
127 #region IEnumerable<List<Cell<T>>> Members
128
129 public IEnumerator<List<Cell<T>>> GetEnumerator()
130 {
131 return _cells.GetEnumerator();
132 }
133
134 #endregion
135
136 #region IEnumerable Members
137
138 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
139 {
140 return _cells.GetEnumerator();
141 }
142
143 #endregion
144 }
这样这代码的抽象度是不是更高些了?在上面泛型类基础上,用扩展方法也好,lambda表达式也好,要计算有道第一题是相当容易了。并且,这两个泛型类的用途远远不止有道第一题那种用途。讨论一下:
(1)想要在这个基础上计算新的测量,很容易;
(2)Cell<T>中的T不仅仅只限于int或double,也可以是任何其它类型,它维护的是一个抽象的类型实例之间的微观关系;
(3)MatrixCellContainer<T>维护的是类型实例之间的宏观关系;
(4)这两个类是不是也可以建模mud游戏的地图?是不是也可以用来建模俄罗斯方块之类的小游戏?。。。。
BTW. 我反对用OO来研究算法 写这篇文章的目的只是 ... 好玩 ...