Considerações de projeto de hierarquia de contrato / projeto / linha de item

5

Atualmente, temos um aplicativo que permite aos usuários criar um Contract . Um contrato pode ter 1 ou mais Project . Um projeto pode ter 0 ou mais subprojetos (que podem ter seus próprios subprojetos e assim por diante), bem como 1 ou mais Line . As linhas podem ter qualquer número de sub-linhas (que podem ter suas próprias sub-linhas e assim por diante).

Atualmente, nosso design contém referências circulares e eu gostaria de me afastar disso. Atualmente, parece um pouco assim:

public class Contract
{
    public List<Project> Projects { get; set; }        
}

public class Project
{
    public Contract OwningContract { get; set; }
    public Project ParentProject { get; set; }
    public List<Project> SubProjects { get; set; }
    public List<Line> Lines { get; set; }
}

public class Line
{
    public Project OwningProject { get; set; }
    public List ParentLine { get; set; }
    public List<Line> SubLines { get; set; }
}

Estamos usando o "padrão" da M-V-VM e usamos esses modelos (e seus modelos de visualização associados) para preencher uma grande tela de "edição" na qual os usuários podem modificar seus contratos e as propriedades em todos os objetos. Onde as coisas começam a ficar confusas para mim é quando adicionamos, por exemplo, uma propriedade Cost ao Line . A questão está refletindo as mudanças de nível mais alto (o contrato) feitas no nível mais baixo.

Procurando por alguns pensamentos sobre como alterar esse design para remover as referências circulares. Um pensamento que eu tinha era que o contrato teria um Dictionary<Guid, Project> que conteria TODOS os projetos (independentemente do seu nível hierárquico). O Project teria então uma propriedade Guid chamada "Parent", que poderia ser usada para pesquisar o dicionário do contrato pelo objeto pai. A mesma lógica pode ser aplicada no nível Line .

Obrigado! Qualquer ajuda é apreciada.

    
por Thelonias 25.10.2012 / 20:41
fonte

1 resposta

2

Aqui estão algumas ideias:

  • O que você descreveu é seu Model , não seu ViewModel . Eu fiz o MVVM em uma estrutura de árvore antes e ficou feio rápido. Seu ViewModel precisa imitar essa estrutura, mas deve usar ObservableCollection em vez de List e pode aceitar mais dados inválidos porque os dados estão em transição enquanto estão editando-os.
  • Crie um código que converterá seu Model em seu ViewModel quando você carregar a tela. Isso permite que você implemente um botão Cancelar que não faz nada.
  • Eu usei eventos para propagar alterações em níveis inferiores na árvore até nós mais altos, e eu recomendaria não fazer isso. Seria melhor se o nó filho acabasse de chamar um método no nó pai, como PriceChanged(decimal oldPrice, decimal newPrice)
  • Considere todas as ações que precisam ser propagadas: novos filhos, reordenar crianças, excluir crianças.
  • Decida de antemão se você deseja implementar a funcionalidade Desfazer porque é extremamente difícil aplicá-la depois. Se você quiser fazer o Undo, sugiro projetar a árvore de modo que cada ação tenha uma ação reversa fácil e óbvia e, em seguida, empurre essa ação inversa para um Stack<Action> . Você pode querer passar uma referência a esse Stack para todos os nós da árvore, para que você não precise passar as ações de desfazer para a árvore para armazenamento. Lembre-se de que, ao fazer com que cada ação tenha uma ação inversa, você também precisa pensar em PropertyChanged eventos, de modo que seu View permaneça sincronizado.
  • Você precisará de um código que valide ViewModel antes de confirmar as alterações no Model e precisará de um código que confirme as alterações.
  • Pense em toda a tarefa como um problema de estrutura de dados. Pré-condições, ações, pós-condições. Se você não usou o desenvolvimento orientado a testes antes, sugiro que este seria um excelente lugar para começar a usá-lo.
por 25.10.2012 / 21:18
fonte