我的项目/计划将跟踪建筑项目图纸的变化,并在更改图纸时向人们发送通知.
将有许多建筑项目(工地),每个建筑项目中都会有很多图纸.每个图纸都会有一些修改(当它们被更改时,会创建一个新版本).
这是我的项目类
public class Project { private readonly List<Drawing> _drawings = new List<Drawing>(30); private readonly List<Person> _autoRecepients = new List<Person>(30); public int ID { get; private set; } public string ProjectNumber { get; private set; } public string Name { get; private set; } public bool Archived { get; private set; } public List<Person> AutoRecepients { get { return _autoRecepients; } } public Project(int id,string projectNumber,string name) { if (id < 1) { id = -1; } ID = id; ProjectNumber = projectNumber; Name = name; } public bool AddDrawing(Drawing drawing) { if (drawing == null) return false; if (_drawings.Contains(drawing)) { return true; } _drawings.Add(drawing); return _drawings.Contains(drawing); } public void Archive() { Archived = true; } public bool DeleteDrawing(Drawing drawing) { return _drawings.Remove(drawing); } public IEnumerable<Drawing> ListDrawings() { return _drawings.AsReadOnly(); } public override string ToString() { return string.Format("{0} {1}",ProjectNumber,Name); } }
这是我的绘画课
public class Drawing : IDrawing { private List<IRevision> _revisions = new List<IRevision>(5); private List<IssueRecord> _issueRecords = new List<IssueRecord>(30); private IRevision _currentRevision; public int ID { get; private set; } public string Name { get; private set; } public string Description { get; set; } public Project Project { get; private set; } public IRevision CurrentRevision { get { return _currentRevision; } } public Drawing(int id,string name,string description,Project project) { // To be implemented } /// <summary> /// Automatically issue the current revision to all Auto Recepients /// </summary> public void AutoIssue(DateTime date) { AutoIssue(date,_currentRevision); } /// <summary> /// Automatically issue a particular revision to all Auto Recepients /// </summary> public void AutoIssue(DateTime date,IRevision revision) { } public void IssueTo(Person person,DateTime date,IRevision revision) { _issueRecords.Add(new IssueRecord(date,this,revision,person)); throw new NotImplementedException(); } public void IssueTo(Person person,DateTime date) { IssueTo(person,date,_currentRevision); } public void IssueTo(IEnumerable<Person> people,DateTime date) { IssueTo(people,_currentRevision); } public void IssueTo(IEnumerable<Person> people,IRevision revision) { foreach (var person in people) { IssueTo(person,revision); } } public void Rename(string name) { if (string.IsNullOrWhiteSpace(name)) { return; } Name = name; } public void Revise(IRevision revision) { if (revision.Name == null ) return; _revisions.Add(revision); _currentRevision = revision; } public struct IssueRecord { public int ID { get; private set; } public DateTime Date { get; private set; } public IDrawing Drawing { get; private set; } public IRevision Revision { get; private set; } public Person Person { get; private set; } public IssueRecord(int id,IDrawing drawing,IRevision revision,Person person) { if (id < 1) { id = -1; } ID = id; Date = date; Drawing = drawing; Revision = revision; Person = person; } } }
这是Revision结构
public struct Revision : IRevision { public int ID { get; private set; } public string Name { get; } public DateTime Date { get; set; } public IDrawing Drawing { get; } public IDrawingFile DrawingFile { get; private set; } public Revision(int id,IDrawingFile drawingFile) { if (name == null) { throw new ArgumentNullException("name","Cannot create a revision with a null name"); } if (drawing == null) { throw new ArgumentNullException("drawing","Cannot create a revision with a null drawing"); } if (id < 1) { id = -1; } ID = id; Name = name; Drawing = drawing; Date = date; DrawingFile = drawingFile; } public Revision(string name,IDrawingFile drawingFile) : this(-1,name,drawing,drawingFile) { } public Revision(string name,IDrawing drawing) : this(-1,DateTime.Today,null) { } public void ChangeID(int id) { if (id < 1) { id = -1; } ID = id; } public void SetDrawingFile(IDrawingFile drawingFile) { DrawingFile = drawingFile; } }
我的问题是在绘图类中的项目引用和修订结构中的绘图引用.
好像有点代码味道?
它似乎也可能导致将来序列化问题.
有一个更好的方法吗?
绘图对象似乎有必要知道它属于哪个项目,这样如果我正在使用单个绘图对象,我就可以知道它们属于哪个项目.
类似地,每个修订版本基本上由图纸“拥有”或者是图纸的一部分.没有绘图,修订没有意义,所以它需要引用它所属的绘图?
任何建议将不胜感激.
解决方法
可以从两端导航的亲子关系.
是的,这是正常的,可接受的,不是代码味道.是的,一些序列化工具需要您提示.例如Newtonsoft.Json需要ReferenceLoopHandling.Ignore设置.
作为一个概念的导航性并不总是在OO设计中被讨论,这是不幸的,因为它只是你想要的概念. (这是UML中的明确术语).
您通常不需要从两端进行导航.父子关系通常仅从父对子编码.这很常见.例如,invoiceline类很少需要其父发票的显式字段,因为大多数应用程序仅在检索父发票后查看该行.
所以设计决定不是,
“没有绘画,修改是否有意义?”
但
“我是否需要找到仅给出修订版的图纸?”
我的猜测是你的修订就像发票行,而不需要导航到他们的父母.图纸的答案< - >项目对我来说并不明显. (这是关于您的域名的分析问题,而不是代码式问题).
这是OO代码与sql之间的显着差异.在sql数据库中,它必须是包含对其父图形ID的引用的修订表.在OO代码中,父类几乎总是拥有对子代的引用.孩子们通常不需要引用他们的父母,因为你访问孩子的唯一方法是已经拥有父母.