Esta é provavelmente uma pergunta para iniciantes, mas eu pesquisei muitos tópicos e não consegui encontrar a mesma situação, embora tenha certeza de que esse tipo de situação acontece o tempo todo.
Meu projeto / programa rastreará alterações nos desenhos em projetos de construção e enviará notificações às pessoas quando os desenhos forem alterados.
Haverá muitos projetos de construção (canteiros de obras), que por sua vez terão muitos desenhos em cada um. Cada desenho terá algumas revisões (conforme eles são alterados, uma nova revisão é criada).
Aqui está minha aula de projeto
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);
}
}
Aqui está minha aula de desenho
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, date, _currentRevision);
}
public void IssueTo(IEnumerable<Person> people, DateTime date, IRevision revision)
{
foreach (var person in people)
{
IssueTo(person, date, 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, DateTime date, IDrawing drawing, IRevision revision, Person person)
{
if (id < 1) { id = -1; }
ID = id;
Date = date;
Drawing = drawing;
Revision = revision;
Person = person;
}
}
}
E aqui está a estrutura de revisão
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, string name, IDrawing drawing, DateTime date, 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, IDrawing drawing, DateTime date, IDrawingFile drawingFile)
: this(-1, name, drawing, date, drawingFile)
{
}
public Revision(string name, IDrawing drawing)
: this(-1, name, drawing, DateTime.Today, null)
{
}
public void ChangeID(int id)
{
if (id < 1) { id = -1; }
ID = id;
}
public void SetDrawingFile(IDrawingFile drawingFile)
{
DrawingFile = drawingFile;
}
}
Minha pergunta é sobre a referência do projeto na classe de desenho e a referência do desenho na estrutura de revisão. Parece um cheiro de código? Também parece que pode causar problemas com a serialização no futuro. Existe uma maneira melhor de fazer isso?
Parece necessário que um objeto de desenho saiba a que projeto pertence, para que, se estiver trabalhando com objetos de desenho individuais, eu possa saber a que projeto eles pertencem.
Da mesma forma, cada revisão é essencialmente "propriedade" de um desenho ou parte dela. Uma revisão não faz sentido sem um desenho, então ela precisa de uma referência ao desenho ao qual pertence?
Qualquer conselho seria muito apreciado.
O que você tem não são tanto referências circulares, mas dois exemplos de
um relacionamento pai-filho que é navegável de ambas as extremidades.
Sim, é normal e aceitável e não, não é um cheiro de código. Sim, algumas ferramentas de serialização exigem que você dê dicas. por exemplo, Newtonsoft.Json deseja a ReferenceLoopHandling.Ignore
configuração.
Navegabilidade como um conceito nem sempre é falado no design OO, o que é lamentável porque é exatamente o conceito que você deseja aqui. (É um termo explícito em UML).
Muitas vezes você não precisa de navegabilidade de ambas as extremidades. Os relacionamentos entre pais e filhos costumam ser codificados apenas de pai para filho. Isso é muito comum. Por exemplo, uma invoiceline
classe raramente precisa de um campo explícito para seu pai invoice
porque a maioria dos aplicativos só olha a linha depois de recuperar a fatura pai.
Portanto, a decisão de design não é,
"Uma revisão faz sentido sem um desenho?"
Mas
"Será que algum dia terei de encontrar um desenho com apenas uma revisão?"
Meu palpite é que suas revisões são como linhas de fatura e não precisam navegar até o pai. A resposta para a relação do projeto dos desenhos <——> não é óbvia para mim. (É uma questão de análise sobre o seu domínio, não uma questão sobre o estilo de codificação).
Há uma diferença notável aqui entre o código OO e, por exemplo, SQL. Em um banco de dados SQL, deve ser a revision
tabela que contém a referência ao seu pai drawing
id
. No código OO, a classe pai quase sempre contém uma referência aos filhos. Os filhos geralmente não precisam de uma referência aos pais porque a única maneira de você acessá-los é já tendo o pai.
Este artigo é coletado da Internet.
Se houver alguma infração, entre em [email protected] Delete.
deixe-me dizer algumas palavras