C# 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; }

我在为我的MVVM项目设计好的体系结构时遇到了一个问题。 我提出了如下建议,请阅读并告诉我这是错误的方法还是正确的方法: 我将有一些界面:

 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)。 不幸的是,它存在一些问题:

  • 所有绑定(命令除外)都将在类*工厂中,这可能会产生误导
  • 在大多数情况下,一个VM将有一个策略实现,因此会有大量代码。另一方面,在未来,客户端可以要求另一个角色(实现),这将更容易(只需实现另一个类-无需编辑旧代码)
  • 你觉得怎么样?或者您使用另一种模式进行业务逻辑

    编辑: Xaml部分:

    <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中看到命令正常,但其他绑定绑定到一个大对象时,可能会感到困惑。就是关于这一点。这条线索是关于这个解决方案是否不违反“规则”,或者对于将来可能加入项目的开发人员来说是否过于误导