单个实例与集合,类似于英文中单数与复数的,例如 photo 和 photos,student 和 students。
如果直接在业务类中使用集合去定义复数,则该集合只承载了容器功能,所有涉及到集合的操作,不可避免地写进了业务类,使得业务类臃肿。另外,由于集合是开放的,数据可在业务类中修改,使得数据被修改不可控。
我们不妨更进一步,从概念上将其抽象为照片与相册,学生与班级等等,不仅具备容器功能,还具备管理集合的功能。一种合乎逻辑的访问方式不仅有助于思考,同时会使得代码简洁易读。
这种编程方式很常见,只是最近在使用中感觉其对手头上的一个项目越发重要。故而整理一个小例子记录之。
以照片和相册为例:
class Photo { public Photo(string name, string path) { Name = name; Path = path; } public string Name; public string Path; public string Note; } class Album { public Album(string name, string subject) { Name = name; Subject = subject; Photos = new Dictionary<string, Photo>(); } public string Name; public string Subject; private Dictionary<string, Photo> Photos; public Photo this[string photoname] { get { if (Photos.ContainsKey(photoname)) { return Photos[photoname]; } else { return null; } } set { if (Photos.ContainsKey(photoname)) { throw new ArgumentException("重复的主键"); } else { Photos.Add(photoname, value); } } } } static void Main(string[] args) {
// Album a = new Album("风景", "高山"); var p1 = new Photo("泰山", @"D: aishan.jpg"); var p2 = new Photo("黄山", @"D:huangshan.jpg"); a[p1.Name] = p1; a[p2.Name] = p2; // var p = a["黄山"]; }
避免将 Photos 这种集合定义在业务类中,因为这往往涉及到集合的操作,而集合的操作可能需要各种附加信息。通过定义 Album 类,可适当添加一些属性和方法,用于管理集合。这种方式可使得业务逻辑类单纯。
扩展:该方法基本上可以看做是《重构》中的“封装集合”。