The problem is this, there is an abstract class of a model from which a certain number of specific models are inherited, they all have a few heap of their own fields except for some common ones, each has its own corresponding View associated, the problem begins in that each instance needs to be wrapped in the appropriate ViewModel (view they are different, and their behavior is different) - now I have a separate function involved in it, it defines a switch to which conditions are added as I write new classes with this signature:

 public static TaskViewModelBase GetTaskViewModel(TaskBase tsk, IDataTask taskDataService) 

All this nonsense smacks badly, as you understand. Is there any elegant solution or architecture chosen to hell?

  • Hm For some reason, you have a one-to-one correspondence between models and view models. This is usually not the case; any VM can use several models. - VladD
  • Well, it happened, and I am not a great programmer. The idea is this - there is a certain task list, each has its own data and its own behavior, and when editing, the user displays a window with settings, for each task, of course, its own. Plus, the data is stored in the database (which is why I began to use inheritance, and not the interface, as I did before, when the database was not yet screwed). I suffer with this for a long time, and I come to the conclusion that I initially thought out badly. - Sergey
  • Well, we're not all geniuses here. See what is easy to generalize, generalize, and what is difficult, well, and God bless him. In any case, a switch by type is not very good. It is probably better to encode the necessary functionality in a specific type. In any case, the function of obtaining a VM by the model should not be needed: the program logic is usually located in the VM, and each VM, in theory, creates a model for itself (or takes it from some known place). - VladD
  • Yes, this is all quite obvious, but as far as I do not fight, I did not find a better solution. - Sergey

1 answer 1

The Visitor pattern fits your task perfectly.

 abstract class Model { public abstract void Visit(IModelVisitor visitor); } class ModelA : Model { public override void Visit(IModelVisitor visitor) { visitor.Visit(this); } } class ModelB : Model { public override void Visit(IModelVisitor visitor) { visitor.Visit(this); } } interface IModelVisitor { void Visit(ModelA modelA); void Visit(ModelB modelB); } abstract class ViewModel { /* ... */ } class ViewModelA : ViewModel { public ViewModelA(ModelA modelA) { /* ... */ } } class ViewModelB : ViewModel { public ViewModelB(ModelB modelB) { /* ... */ } } class ViewModelFactory : IModelVisitor { private ViewModel _viewModel; public ViewModel CreateViewModel(Model model) { model.Visit(this); return _viewModel; } void IModelVisitor.Visit(ModelA modelA) { _viewModel = new ViewModelA(modelA); } void IModelVisitor.Visit(ModelB modelB) { _viewModel = new ViewModelB(modelB); } } 

Example of use:

 var factory = new ViewModelFactory(); var viewModel = factory.CreateViewModel(new ModelB()); // returns ViewModelB. 
  • Gash, works, but somehow I don’t see what a profit is, it looks like the same eggs are only on the side) - Sergey
  • The profit is that instead of the switch block one of the OOP principles is used - polymorphism. Switch blocks scattered throughout the code do not protect you from errors in any way, unlike Visitor, in which you simply cannot add a new class to the hierarchy without updating IModelVisitor and the corresponding implementations. - Raider
  • Well, yes, he drove, and he himself realized, unless it is just unusual. Thanks - Sergey