This is a WPF application using MVVM design that connects to Services (Business logic layer) which manage Models, with an exception that some property set of the model is bound to some views directly. This means the model properties are updated without involving ViewModel in some cases and this view scheme cannot be changed because of specific integration limitations.
The requirement is that in many cases, the property change in model involves some business logic to be performed in the Service that in turn updates other properties of the model and updates(CRUD) other models in the service too.
The two approaches that I thought of,
The model has Service reference. The property-set call performs the service operation. But, I do not think it is a proper design strategy to do so, what are the thoughts on this?
class Model { public int Property1 { get => _property1; set { _property1 = value; Service.PerformOperation(); OnPropertyChanged(); } } }
Service subscribes to events of Models.
class Service { private void ModelPropertyChanged(object sender, EventArgs e) { if (e.PropertyName == "Property1") { PerformOperation(); } } }
What is the better design strategy recommended in this type of scenarios?
=========================
Based on the answer [@Robert Harvey]
Introduce a Service-Model Worker between Service and Model and set Model properties through the Service-Model Worker. This ensures loose-coupling and keeps the Model less Anemic.
class Model
{
public Model(IServiceWorker serviceWorker)
{
}
public int Property1
{
get => _property1;
set
{
_serviceWorker.SetProperty(
nameof(Property1),
value,
() => { _property1 = value; });
}
}
}
class ServiceWorker : IServiceWorker
{
public void SetProperty(string propertyName, object value, Action setPropertyInternal)
{
switch (propertyName)
{
case nameof(_model.Property1):
{
//preview property change
//(validation and other cancellable checks)
IModelValidator.Validate(propertyName, value);
//Before property changed
Service.PerformOperation_BeforePropertyChanged();
//Set property
setPropertyInternal();
//On Property change
Service.PerformOperation();
_model.RaisePropertyChanged(propertyName);
}
break;
}
}
}