C# MVVM逻辑体系结构
我在为我的MVVM项目设计好的体系结构时遇到了一个问题。 我提出了如下建议,请阅读并告诉我这是错误的方法还是正确的方法: 我将有一些界面:C# MVVM逻辑体系结构,c#,mvvm,xamarin.forms,C#,Mvvm,Xamarin.forms,我在为我的MVVM项目设计好的体系结构时遇到了一个问题。 我提出了如下建议,请阅读并告诉我这是错误的方法还是正确的方法: 我将有一些界面: public interface ISomeStrategy { void LoadData(); void Search(string text); IList<SomeObject> SomeObjectsList { get; set; }
public interface ISomeStrategy
{
void LoadData();
void Search(string text);
IList<SomeObject> SomeObjectsList { get; set; }
}
public class FirstStrategy: INotifyPropertyChanged, ISomeStrategy
{
public CompositePayslipItem(IDataService dataService)
{
DataService = dataService;
}
private IDataService DataService;
public IList<SomeObject> SomeObjectList{get; set;}
public async void LoadData()
{
SomeObjectList =await DataService.GetAll();
}
public async void Search(string text)
{
SomeObjectList =await DataService.GetByKey(text);
}
}
公共接口策略
{
void LoadData();
无效搜索(字符串文本);
IList SomeObjectsList{get;set;}
}
以及实现此接口的类:
public interface ISomeStrategy
{
void LoadData();
void Search(string text);
IList<SomeObject> SomeObjectsList { get; set; }
}
public class FirstStrategy: INotifyPropertyChanged, ISomeStrategy
{
public CompositePayslipItem(IDataService dataService)
{
DataService = dataService;
}
private IDataService DataService;
public IList<SomeObject> SomeObjectList{get; set;}
public async void LoadData()
{
SomeObjectList =await DataService.GetAll();
}
public async void Search(string text)
{
SomeObjectList =await DataService.GetByKey(text);
}
}
公共类优先策略:INotifyPropertyChanged,ISomeStrategy
{
公共CompositePayslipItem(IDataService数据服务)
{
数据服务=数据服务;
}
私有IDataService数据服务;
公共IList SomeObjectList{get;set;}
公共异步void LoadData()
{
SomeObjectList=等待DataService.GetAll();
}
公共异步无效搜索(字符串文本)
{
SomeObjectList=await DataService.GetByKey(文本);
}
}
和视图模型:
public void SomeViewModel
{
public SomeViewModel(IDataService dataService)
{
Strategy = new FirstStrategy(dataService);
Strategy.LoadData();
}
public ISomeStrategy Strategy {get; set;}
private Command<string> searchCommand;
public Command<string> SearchCommand => searchCommand?? (searchCommand= new Command(ExecuteSearchCommandAsync));
private async void ExecuteSearchCommandAsync(string text)
{
Strategy.Search(text);
}
}
公共视图模型
{
公共SomeViewModel(IDataService数据服务)
{
策略=新的第一策略(数据服务);
Strategy.LoadData();
}
公共策略策略{get;set;}
专用命令搜索命令;
公共命令SearchCommand=>SearchCommand??(SearchCommand=newcommand(ExecuteSearchCommandAsync));
专用异步void ExecuteSearchCommandAsync(字符串文本)
{
战略.搜索(文本);
}
}
正如您所看到的,所有逻辑都将在“Strategy”类中,这些类将通过ViewModel绑定到View。它给了我什么?我可以在运行时动态更改实现。例如,如果我有一名员工和一名经理,搜索和获取数据的逻辑不同,我可以实现另一个类并更改属性策略,而无需编辑员工的现有代码(许多方法中没有额外的if)。
不幸的是,它存在一些问题:
<ContentPage
x:Class="Test.SomePage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<StackLayout>
<SearchBar
HeightRequest="50"
SearchCommand="{Binding SearchCommand}" />
<ListView
x:Name="formatsList"
Margin="0"
ItemsSource="{Binding Strategy.SomeObjectList}">
</StackLayout>
</ContentPage>
试图帮助您,希望我理解您的问题: 所有绑定(命令除外)都将在类工厂中,这可能会产生误导:我假设您绑定到viewmodel,而不是直接绑定到策略 您应该绑定到视图模型,从那里与您的策略交互。否则,您将混合您的层 更新 据我所知,这不是一个问题,一个典型的程序员应该能够立即发现它 如果SomeObject是来自业务层的一种模型,那么您就是在打破层分离参数。未来的开发人员可能看不到重命名SomeObject中的属性的后果。如果某个对象是视图模型的一部分,则您是安全的。请注意;我倾向于过度设计事物;-) <> P> >您可以考虑为<代码>某个对象< /代码>创建一个专用的VIEW模型,并使用<代码> AutoPuffer-<代码>映射到与业务相关的模型。 在大多数情况下,一个VM将有一个策略实现,因此会有大量代码。另一方面,在未来,客户端可以要求另一个角色(实现),这将更容易(只需实现另一个类-无需编辑旧代码) 我在这里找不到问题。一般来说,使用设计模式在前期需要花费更多的精力,以帮助您处理以后不断变化的需求 欲了解更多信息;请参阅此(我的XD)帖子:
关于您的代码的更多建议,免责声明:有些是基于意见的:
在构造函数中加载数据是不好的做法。
public SomeViewModel(IDataService dataService)
{
//`new` issue
Strategy = new FirstStrategy(dataService);
}
典型的加载操作应该是非阻塞和async
,以保持UI响应
public SomeViewModel(IDataService dataService)
{
//load data in constructor issue
Strategy.LoadData();
}
如果为空,则创建新对象。如果多个线程调用此属性,则可能会发生争用情况。考虑<代码>锁定(可能使用显式设置方法),或者在构造函数中初始化。 我认为这在您的代码中并不是一个真正的问题,因为您提到了工厂,但是: 调用
new
使用混凝土,而不是接口。使用工厂或IoC(带解析器,即工厂)解决此问题。
public SomeViewModel(IDataService dataService)
{
//`new` issue
Strategy = new FirstStrategy(dataService);
}
不要使用
异步无效
首选异步任务
看
可能的(棘手的)比赛条件 在这方面:
public Command<string> SearchCommand =>
searchCommand?? (searchCommand= new Command(ExecuteSearchCommandAsync));
public命令SearchCommand=>
搜索命令??(searchCommand=new命令(ExecuteSearchCommandAsync));
谢谢您的回答。从技术上讲,我仍然会在ViewModel中绑定,但我会将列表直接放在VM中,并将其放在策略中。然后在我看来,我将使用{Binding Strategy.SomeObjectList}来代替{Binding SomeObjectList}关于Dislaimer:我只是快速编写这段代码来表达我的想法。我知道你的建议,以及这段代码中的一些错误做法:)@straiser:啊,很好。继续做好设计模式的工作!:-)你能用XAML/绑定部分更新你的问题吗?我添加了XAML部分,我明白你关于宝贵评论的观点。在这种情况下,我并不真正理解您的第一个问题:所有绑定(命令除外)都将在类*工厂中,这可能会产生误导。理论上,当有人在ViewModel中看到命令正常,但其他绑定绑定到一个大对象时,可能会感到困惑。就是关于这一点。这条线索是关于这个解决方案是否不违反“规则”,或者对于将来可能加入项目的开发人员来说是否过于误导