MVVM逻辑架构

时间:2018-03-07 10:12:51

标签: c# mvvm xamarin.forms

我在为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);
     }

}

和ViewModel:

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);
  }
}

正如您所看到的,所有逻辑都将出现在“策略”类中,这些类将通过ViewModel绑定到View。它给了我什么?我可以在运行时动态地更改实现。例如,如果我有一个Employee和Manager,其中搜索和获取数据的逻辑不同,我可以实现另一个类并更改属性ISomeStrategy Strategy而无需编辑Employee的现有代码(在许多方法中没有其他的)。 不幸的是,它有一些问题:

  1. 所有绑定(命令除外)都在类* Factory中,可能会产生误导性
  2. 在大多数情况下,一个VM将具有一个策略实现,因此将会有大量代码。另一方面,将来客户端可以要求另一个角色(实现),它将更容易(只需实现另一个类 - 不编辑旧代码)。
  3. 你怎么看?或者您可能使用其他模式进行业务逻辑?

    编辑: 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>
    

1 个答案:

答案 0 :(得分:3)

试图帮助你,希望我理解你的问题:

  

所有绑定(命令除外)都在类 Factory中,这可能会误导:我假设您绑定到viewmodel而不是直接绑定到策略。

您应该绑定到视图模型,从那里与您的策略进行交互。否则你正在混合你的图层。

更新

据我所知,不是问题,一个典型的程序员应该能够立即发现它。

如果SomeObject是业务层中的一种模型,则会破坏图层分离参数。未来的开发者可能不会看到例如在SomeObject中重命名属性。如果SomeObject是视图模型的一部分而不是您的安全。请注意;我倾向于过度设计事物; - )

因此,您可以考虑为SomeObject创建专用的视图模型,并使用automapper映射到与业务相关的模型。

  

在大多数情况下,一个VM将具有一个策略实现,因此将会有大量代码。另一方面,将来客户端可以要求另一个角色(实现),它将更容易(只需实现另一个类 - 不编辑旧代码)。

我无法在这里找到问题或疑问。作为一般规则,使用设计模式需要先付出更多努力,以帮助您在以后处理不断变化的需求。

了解更多信息;看到这个(我的XD)帖子:ViewModels in MVC / MVVM / Seperation of layers- best practices?

有关您的代码的更多建议,免责声明:有些是基于意见的:

<小时/> 在构造函数中加载数据是不好的做法。

典型的加载操作应该是非阻塞的async以保持UI响应。

public SomeViewModel(IDataService dataService)
{
   //load data in constructor issue
   Strategy.LoadData();
}

如果为null,则表示正在创建新对象。如果多个线程正在调用此属性,则可能会出现争用情况。考虑lock(可能使用显式set方法),或在构造函数中初始化。 我认为,自从您提到 Factory 之后,这在您的代码中确实存在问题,仍然是:

调用new使用混凝土,而不是接口。使用工厂或IoC(使用旋转变压器,即工厂)来解决此问题。

public SomeViewModel(IDataService dataService)
{
    //`new` issue
    Strategy = new FirstStrategy(dataService);
}

<小时/> 请勿使用async void首选async Task

请参阅async/await - when to return a Task vs void?

//use Task if possible
private async void ExecuteSearchCommandAsync(string text)

可能(棘手的)竞争条件

在这一行:

public Command<string>  SearchCommand => 
   searchCommand?? (searchCommand= new Command(ExecuteSearchCommandAsync));